Sunday, April 10. 2011
Glassfish Enterprise Profile on Linux amd64
The previous week an ex co-worker, and a good friend, asked me if I had tested Glassfish 2.1.1 on a x64 linux box. The question surprised me cos my new laptop is an amd64 Linux installation, all my glassfish tests are done in it and I had not noticed any problem. He clarified me that he could not setup an enterprise profile. I remember that Glassfish 2.1.1 has no difference between open source and supported edition (it was based on the same source code), so this entry is about how to setup a Glassfish enterprise profile in Linux x64 using its community version.
Glassfish v2 can be installed using three different profiles: developer, cluster or enterprise. Developer profile is a single application server instance. Cluster is a multi-instance setup with central management for all servers and cluster/Load Balancing features enabled. Enterprise profile is exactly like cluster but using NSS (Netscape Security Services) instead of JKS (Java KeyStore) for the certificate store and the possibility of using HADB for session management (a kind of multinode database that Sun used to integrate with Glassfish to get the third type of session-aware cluster I talked about in a previous post). My friend explained to me that the problem was with NSS libraries (supported Glassfish edition includes them), the libraries provided by the Linux distribution were ELF 32-bit and, obviously, they do not work with a 64 bit JVM and system.
I am going to explain the steps I followed testing this issue. This is usually how I like to show my entries, because I think this way is more useful and it is also better for me to remember.
-
As the Glassfish documentation comments, in open source edition NSS and NSPR libraries have to be installed independently from glassfish. In my debian box this step was easily done.
$ apt-get install libnss3-1d libnss3-tools libnspr4-0d libnspr4-dev libnss3-dev
Developer packages were not needed at this time but following points are going to use them.
-
Glassfish installer for open source edition was downloaded from glassfish site. For linux only one package is available. Cluster setup was installed using glassfish instructions.
$ java -Xmx256m -jar glassfish-installer-v2.1.1-b31g-linux.jar $ cd glassfish $ lib/ant/bin/ant -f setup-cluster.xml
Glassfish community edition is installed in the directory where the installer is launched, inside a new glassfish folder (this installation directory will be denoted ${GLASSFISH_DIR} since now). By default the previous process creates a domain (domain1) using cluster profile (not enterprise). So this domain was deleted.
$ cd ${GLASSFISH_DIR}/bin $ ./asadmin delete-domain domain1
-
The configuration file ${GLASSFISH_DIR}/config/asenv.conf was modified to include where NSS are installed (debian installs main NSS and NSPR libs in /usr/lib). So the following properties were modified:
AS_NSS="/usr/lib" AS_NSS_BIN="/usr/bin"
-
If you try to create an enterprise profile domain just like this the issue explained by my colleague happens. It seems a internal libasnss.so is also used and glassfish only provides it in 32 bit mode (as you see in the download page there is no Linux x64 installer). But this is open source so, not wasting any time, I took a look to glassfish 2.1.1 subversion and I found a nssstore.c file. This is a Java Native Interface (JNI) wrapper above NSS library (Java can call native libraries using JNI and this file is a wrapper to make the interaction easier). Although there are some links for completely building glassfish (one for glassfish v3 and another outdated one for v2), I quickly gave up because the process seems to be huge. So I decided to only compile the problematic file.
First the directory that contains this file was checked out:
$ cd /tmp $ svn checkout https://svn.java.net/svn/glassfish~v2/trunk/appserv-native-ee $ cd appserv-native-ee/src/cpp/nssutil/
After that the header file has to be made. In JNI this is done reading the class and executing javah command on it (the problematic class, source of the exception, was com.sun.enterprise.ee.security.NssStore).
$ javah -classpath ${GLASSFISH_DIR}/lib/appserv-se.jar \ -o com_sun_enterprise_ee_security_NssStore.h com.sun.enterprise.ee.security.NssStore
With this header the C file can be compiled against NSS/NSPR debian 64 bits libraries:
$ gcc -fpic -I/usr/lib/jvm/java-6-sun-1.6.0.24/include/ \ -I/usr/lib/jvm/java-6-sun-1.6.0.24/include/linux/ \ -I/usr/include/nss/ -I/usr/include/nspr/ nssstore.c -c $ gcc -shared -Wl,-rpath,${GLASSFISH_DIR}/lib -o libasnss.so nssstore.o -lc \ -L/usr/lib -lnss3 -lnspr4 -lnssutil3 -lsmime3
The new libasnss.so library is copied to glassfish lib directory (a backup is previously done).
$ cp ${GLASSFISH_DIR}/lib/libasnss.so ${GLASSFISH_DIR}/lib/libasnss.so.ORIG $ cp libasnss.so ${GLASSFISH_DIR}/lib/libasnss.so
-
After the previous step the domain is successfully created but it fails to start. It complains about library /usr/lib/amd64/libsoftokn3.so does not exist. Looking again the code of the class EESecuritySupportImpl.java (thrower of the new exception) it tries to initialize the PKCS11 provider (method initNSS) with the libsoftokn3 NSS library compounding its path as follows: the AS_NSS path from asenv.conf (in our case /usr/lib), the architecture if system is 64 bits (amd64 in our case) and finally libsoftokn3.so if system is not windows. So the result is /usr/lib/amd64/libsoftokn3.so but, in case of debian, this library is located in /usr/lib/nss.
I did not think too much and, after becoming root, I created a link.
# cd /usr/lib # ln -s nss amd64
-
Finally the enterprise domain was created and started successfully.
$ cd ${GLASSFISH_DIR}/bin $ ./asadmin create-domain --profile enterprise --user admin --adminport 9898 \ --savelogin=true --savemasterpassword=true domain1 $ ./asadmin start-domain
Here it is a video where the new domain is created and started (as you see my architecture is amd64, the certificate store is NSS and glassfish works perfect).
As a conclusion the glassfish installer for Linux is only provided in 32 bits. It works in x64 Linux system using developer and cluster profile cos a complete Java stack is used (no JNI library is needed) but it fails in enterprise. The enterprise profile uses NSS as the certificate store and a little libasnss.so (JNI library) is provided for easier integration, but it is only in 32 bit. In this entry the library was re-compiled in my amd64 box. Of course another problems could come out cos I did not test all the features and maybe more libraries are used (there are more native libraries in the lib glassfish directory and all of them are 32 bit).
That's the Way I Wanna Rock 'n' Roll!
Saturday, March 19. 2011
Friday Night Fever (or How a Computer Guy Spends the Friday Night)
For some strange reasons this week I needed to use my Spanish eID (DNIe) again and, sometimes these things happen, firefox hanged like crazy. Finally I had to reboot my system to use the platform pre-installed windows to complete the formality. Yesterday night I decided to find out what the hell was going on here.
As always I put opensc in debug mode (setting debug to 10 in /etc/opensc/opensc.conf) and what I saw was really amazing. Starting firefox (iceweasel) inside a terminal the debug dumped like crazy but it sometimes hanged for exactly 60 seconds. So it was not totally frozen, it worked quite well but sometimes it was waiting for something one minute. The problem is opensc calls a lot to the card and firefox hangs at least two or three times every startup (which means more than two or three minutes waiting firefox to come up).
First thing to always check in these situations is what has been changed (I have a thing about upgrading my Debian laptop). Since the time I wrote the DNIe entry the opensc packages (the project that deals with PKCS#11 and PKCS#15) remain the same, PC/SC lite (the project for communicating with smartcards and readers) has been upgraded from 1.5.5 to 1.6.6 and libccid (the handler library for my reader) from 1.3.11 to 1.4.2. I decided to come back to original packages (uninstalling and installing the old ones) to see what happened and, voilà, it started to work as before, no watings.
At that moment I was not totally happy cos I do not feel comfortable when I do not know what really happens and, even less, holding packages. So I started compiling by myself the complete software stack, first PC/SC lite 1.7.0, then libccid 1.4.2 and then opensc 0.12.1. But with opensc I changed my mind and I compiled it twice. First the old source from DNIe official page (opensc-dnie), the external library I talked about in the old entry, and opendnie (see this mail and this spanish blog), the effort of a Spanish guy to re-implement all the stuff to include Spanish eID into opensc without legal issues (maybe this work deserves a new entry). I had been thinking about opendnie for some time but I had never had the time to test it. The old source code for opensc-dnie now does not compile, the problem is libassuan (the little window the library shows when you are about to sign something) has changed its api. But checking opensc patch the modification of dialog.c was easy (here it is the patch if you want to use it). Opendnie compiled with no issues.
Testing and debugging I realized the problem was not in any of these packages but in libusb (the spurious hang also happened in my compiled versions and it did not matter you use opendnie or opensc-dnie). Now libccid 1.4.x is linked against libusb-1.0 (thing that did not happen with 1.3.x) and this is the reason the bug came out after the upgrade. So I also compiled libusb 1.0.8 and I saw the problem was inside libusb_control_transfer function. This function sends the transfer to the usb device and then waits for the response with a 60 seconds timeout. Finally I changed the fixed 60 seconds and tried again. And it worked, both solutions (opendnie and opensc-dnie) hanged no more. My patch was very crappy and straight forward but I opened a bug against libusb. At that time it was around 2 am at night and I had not even dinner. You know... it was a computering Friday night fever!
Today in the morning Ludovic Rousseau (the PC/SC and CCID guy) answered me saying this bug was known. He opened a ticket six months ago with a resolution patch inside but it is not closed yet (and Ludovic seems not very happy with that). I sent another post saying my issue can therefore be closed and then I tested Ludovic's patch. The patched libusb also worked correctly so I sent a final comment to Ludovic's ticket saying his patch fixed my issue (at this moment both posts are not displayed cos libusb moderates the comments). And that is all. I do not know how other jobs are but we are masochists and (worst of all) we enjoy it.
See you next time!
Tuesday, May 25. 2010
Making a SUDOKU using CGI
First of all the sudoku itself must to be design. The user is supposed to fill the sudoku (copying from the newspaper or the magazine) and then call Antonio's CGI in order to solve the quiz. The sudoku is designed like a 9x9 text input square. Of course some CSS is used to make the boxes look like the famous sudoku board. Besides a little javascript is incorporated to avoid the user to type something different than numbers (from 1 to 9). The HTML stuff consists of three files:
- index.html: The main HTML page that has the sudoku to fill and a submit and reset button. The text inputs are called cXY where X and Y are the sudoku cell, from 1 to 9.
- sudoku.css: CSS style sheet to make the text inputs similar to a sudoku board, the tricky part for joining the boxes is to use negative numbers in margin tag.
- sudoku.js: The onlyNumbers javascript function which avoids typing something different from numbers.
The final result is the empty sudoku board I present below.
Now the user can fill the sudoku the CGI part takes the turn. CGI is an old technique that let any executable (C, perl or whatever) to be integrated into a web server. The executable receives typical web parameters via environment variables (QUERY_STRING, REQUEST_URI, HTTP_USER_AGENT and many others) and it generates the HTML code directly writing to standard output. It is clear this technique is not the best in terms of performance (every call to the CGI means a fork, initialization and execution) and that is the reason CGI were obsoleted by other multi-threaded, tightly coupled solutions like FastCGI, SCGI, Servlets, mod_perl or PHP.
Going back to our sudoku problem when the user presses the submit button all the text inputs are sent to the CGI. As you know an HTTP form can send information via GET or POST. The GET method adds all the parameters to the QUERY_STRING, for example GET submit of the sudoku form results in the following URL:
http://server:port/cgi-bin/sudoku?c11=1&c12=&c13=&c14=8&...
So the CGI receives all the cell data inside QUERY_STRING environment variable. Parameters are sent using pairs name=value and separated each other with an ampersand (&). Besides values are encoded to avoid non-ascii characters.
But if POST submit is used the parameters are sent in the body of the message. I mean, using GET all the data is in the URL and no body is sent in the HTTP message but using POST the URL has no parameters and all of them are written in the HTTP body. The CGI receives the body as standard input, i.e. the CGI has to read the standard input (parameters are sent exactly the same way as GET, encoded and separated with an ampersand).
In summary, a little sudoku.c is presented. The program performs the following steps:
- The sudoku representation is a int[10][10] matrix array. I know I am wasting the 0 row and 0 column but it does not matter cos my representation is pointless (Antonio representation is the meaningful).
- Matrix is reset to 0 (9x9 board is set to 0).
- The program receives the cXY parameters (using QUERY_STRING or standard input, GET or POST) and fills the sudoku matrix. The non-empty parameters are placed in the corresponding cells (the remaining cells are still zero). The final solution must be modified to assign cXY parameters to the correct sudoku representation. For this part I copied some code from cgiparse.c of W3C (parsing and decoding stuff).
- Nothing. The four step would be resolving the sudoku but my example is just an empty box (Antonio you have to insert your code here).
- The HTML is generated to the standard output. The page is just the same to the first one but the inputs are readonly (they are non modifiable). My empty example just returns the same sudoku previously sent but with 0's in the not filled cells.
In order to compile the c program it is just needed the simplest gcc command:
$ gcc -o sudoku sudoku.c
The final point is how to put the CGI inside a web server. My CGI example deserves to run inside Apache web server. Apache is the everlasting open source web server, it is very complete and robust but a bit heavy. Now there are other web servers which out-perform Apache mainly when not a full-featured web server is needed (lightweight httpd).
To run the example inside Apache we need to move our static content inside the docroot in a /sudoku directory (references of the generated HTML are pointing this directory). This way if the /var/apache2/htdocs is the docroot of the Apache we set the following files:
/var/apache2/htdocs/sudoku/index.html
/var/apache2/htdocs/sudoku/sudoku.css
/var/apache2/htdocs/sudoku/sudoku.js
And the sudoku binary must be placed inside a cgi-bin directory. Any Apache installation usually has a CGI directory, for example in my box this is the line of the httpd.conf configuration file that defines the cgi-bin:
ScriptAlias /cgi-bin/ "/var/apache2/cgi-bin/"
Any binary placed inside /var/apache2/cgi-bin/ acts as a CGI program, so our sudoku binary must be moved there:
/var/apache2/cgi-bin/sudoku
And the URI to call it is /cgi-bin/sudoku. If you check the index.html file, its form has the action pointing to this binary.
And it is done. Antonio use the comments part if you have any doubt (this way I am sure you will not make me crazy and you will try your best before asking).
Good luck!
Comments