Here is an example for Java Native Interface
Java application that calls a C function and executes the operation.
Example
Ping program
Step1:
Write a java program for ping operation.
import java.util.StringTokenizer;
public class PINGMain {
String ipaddress = null;
boolean defragment = false;
int num = 2;
String success ="success";
String[] ipaddr = { "www.yahoo.com", "20", "2000", "5000", "500" };
private String destination;
private String packetSize;
private String bytes;
private String time;
private String ttl;
protected native String ping(String[] ipaddress);
public PINGMain() {
super();
try {
System.loadLibrary("ping");
} catch (UnsatisfiedLinkError e) {
e.printStackTrace();
}
singlePing();
}
private void singlePing() {
int a = 10;
int b = 20;
String string=null;
while(true) {
string = ping(ipaddr);
//System.out.println(string);
StringTokenizer strToken = new StringTokenizer(string);
int numToken = strToken.countTokens();
destination = strToken.nextToken();
bytes = strToken.nextToken();
time= strToken.nextToken();
ttl = strToken.nextToken();
System.out.println("\n Reply from"+" "+destination+" "+"bytes"+" "+bytes+" "+"Time"+" "+time+" "+"TTL"+" "+ttl);
}
}
private String continuousPing() {
return null;
}
private String disconnect() {
//unLoadPing();
//System.out.println("Unloaded SuccessFully");
return success;
}
private void unLoadPing() {
// unLoad();
}
/**
* @return
*/
private String getStatistics() {
return null;
}
public static void main(String ar[]) {
new PINGMain();
}
}
Step 2:
Using javac to compile the PINGMain source file
After you have defined the PINGMain class, save the source code in a file called PINGMain .java. Then compile the source file using the javac compiler as follows:
javac PINGMain.java
This command will generate a PINGMain.class file in the current directory.
Step 3:
Using javah -jni to generate a C header file (PINGMain.h) containing the function prototype for the native method implementation
Next we will use the javah tool to generate a JNI-style header file that is useful when implementing the native method in C. You can run javah on the PINGMain class as follows:
javah -jni PINGMain
The command shown above generates a file named PINGMain.h.
Step 4:
Writing the C implementation (PINGMain.c) of the native method
The JNI-style header file generated by javah helps you to write C or C++ implementations for the native method. The function that you write must follow the -prototype specified in the generated header file.
#pragma comment(lib, "wsock32.lib")
#include "jni.h"
#include "com_dtt_traffic_ping_PINGMain.h"
#include "stdlib.h"
#include "StdAfx.h"
#include <windows.h>
#include <winsock.h>
#include <stdio.h>
#include <string.h>
int packetsize;
int count;
char *data;//Ping info
typedef struct tagIPINFO
{
u_char Ttl; // Time To Live
u_char Tos; // Type Of Service
u_char IPFlags; // IP flags
u_char OptSize; // Size of options data
u_char FAR *Options; // Options data buffer
}IPINFO, *PIPINFO;
typedef struct tagICMPECHO
{
u_long Source; // Source address
u_long Status; // IP status
u_long RTTime; // Round trip time in milliseconds
u_short DataSize; // Reply data size
u_short Reserved; // Unknown
void FAR *pData; // Reply data buffer
IPINFO ipInfo; // Reply options
}ICMPECHO, *PICMPECHO;
// ICMP.DLL Export Function Pointers
HANDLE (WINAPI *pIcmpCreateFile)(VOID);
BOOL (WINAPI *pIcmpCloseHandle)(HANDLE);
DWORD (WINAPI *pIcmpSendEcho)
(HANDLE,DWORD,LPVOID,WORD,PIPINFO,LPVOID,DWORD,DWORD);
//
//
char *pingFun(char *dest[])
{
int timeout;
char ping_Resp[2048];
WSADATA wsaData; // WSADATA
ICMPECHO icmpEcho; // ICMP Echo reply buffer
HANDLE hndlIcmp; // LoadLibrary() handle to ICMP.DLL
HANDLE hndlFile; // Handle for IcmpCreateFile()
LPHOSTENT pHost; // Pointer to host entry structure
struct in_addr iaDest; // Internet address structure
DWORD *dwAddress; // IP Address
IPINFO ipInfo; // IP Options structure
int nRet; // General use return code
DWORD dwRet; // DWORD return code
int x;
packetsize = atoi(dest[2]);
count = atoi(dest[5]);
timeout = atoi(dest[4]);
// Dynamically load the ICMP.DLL
hndlIcmp = LoadLibrary("ICMP.DLL");
if (hndlIcmp == NULL)
{
fprintf(stderr,"nCould not load ICMP.DLLn");
return;
}
// Retrieve ICMP function pointers
pIcmpCreateFile = (HANDLE (WINAPI *)(void))
GetProcAddress(hndlIcmp,"IcmpCreateFile");
pIcmpCloseHandle = (BOOL (WINAPI *)(HANDLE))
GetProcAddress(hndlIcmp,"IcmpCloseHandle");
pIcmpSendEcho = (DWORD (WINAPI *)
(HANDLE,DWORD,LPVOID,WORD,PIPINFO,LPVOID,DWORD,DWORD))
GetProcAddress(hndlIcmp,"IcmpSendEcho");
// Check all the function pointers
if (pIcmpCreateFile == NULL ||
pIcmpCloseHandle == NULL ||
pIcmpSendEcho == NULL)
{
fprintf(stderr,"nError getting ICMP proc addressn");
FreeLibrary(hndlIcmp);
return;
}
// Init WinSock
nRet = WSAStartup(0x0101, &wsaData );
if (nRet)
{
fprintf(stderr,"nWSAStartup() error: %dn", nRet);
WSACleanup();
FreeLibrary(hndlIcmp);
return;
}
// Check WinSock version
if (0x0101 != wsaData.wVersion)
{
fprintf(stderr,"nWinSock version 1.1 not supportedn");
WSACleanup();
FreeLibrary(hndlIcmp);
return;
}
// Lookup destination
// Use inet_addr() to determine if we're dealing with a name
// or an address
iaDest.s_addr = inet_addr(dest[1]);
if (iaDest.s_addr == INADDR_NONE)
pHost = gethostbyname(dest[1]);
else
pHost = gethostbyaddr((const char *)&iaDest,
sizeof(struct in_addr), AF_INET);
if (pHost == NULL)
{
fprintf(stderr, "n%s not foundn", dest[1]);
WSACleanup();
FreeLibrary(hndlIcmp);
return;
}
// Tell the user what we're doing
/*printf("nPinging %s [%s]", pHost->h_name,
inet_ntoa((*(LPIN_ADDR)pHost->h_addr_list[0])));*/
// Copy the IP address
dwAddress = (DWORD *)(*pHost->h_addr_list);
// Get an ICMP echo request handle
hndlFile = pIcmpCreateFile();
// for (x = 0; x < 4; x++)
// Set some reasonable default values
ipInfo.Ttl =dest[3];
ipInfo.Tos = 0;
ipInfo.IPFlags = 0;
ipInfo.OptSize = 0;
ipInfo.Options = NULL;
//icmpEcho.ipInfo.Ttl = 256;
// Reqest an ICMP echo
dwRet = pIcmpSendEcho(
hndlFile, // Handle from IcmpCreateFile()
*dwAddress, // Destination IP address
packetsize, // Pointer to buffer to send
0, // Size of buffer in bytes
&ipInfo, // Request options
&icmpEcho, // Reply buffer
sizeof(struct tagICMPECHO),
timeout); // Time to wait in milliseconds
// Print the results
iaDest.s_addr = icmpEcho.Source;
/* printf("\n Reply from %s Time=%ldms TTL=%d",
inet_ntoa(iaDest),
icmpEcho.RTTime,
icmpEcho.ipInfo.Ttl);*/
sprintf(ping_Resp,"%s %d %ld %d",
inet_ntoa(iaDest),
packetsize,
icmpEcho.RTTime,
icmpEcho.ipInfo.Ttl);
if (icmpEcho.Status)
{
// printf("nError: icmpEcho.Status=%ld",
// icmpEcho.Status);
printf("\n Request timed out");
//break;
}
//printf("\n");
// Close the echo request file handle
pIcmpCloseHandle(hndlFile);
FreeLibrary(hndlIcmp);
WSACleanup();
return ping_Resp;
}
JNIEXPORT jstring JNICALL Java_com_dtt_traffic_ping_PINGMain_ping
(JNIEnv *env, jclass job, jobjectArray oarr)
{
jsize argc = (*env)->GetArrayLength(env, oarr);
/* Declare a char array for argv */
int i;
char const* argv[128];
for (i = 1; i < 6; i++)
{
/* obtain the current object from the object array */
jobject myObject = (*env)->GetObjectArrayElement(env, oarr, i-1);
/* Convert the object just obtained into a String */
const char *str = (*env)->GetStringUTFChars(env,myObject,0);
/* Build the argv array */
argv[i] = str;
}
data=(char *)malloc(sizeof(char) * 2048);
sprintf(data,"%s",pingFun(argv),"-10000");
// printf("Data %s ",data);
return ((*env)->NewStringUTF(env,data));
}
Step5:
Compiling the C implementation into a native library, creating ping.dll or libPINGMain.so
On Solaris or Linux, the following command builds a shared library called libPINGMain.so:
cc -G -I/java/include -I/java/include/solaris
PINGMain.c -o libPINGMain.so
On Win32, the following command builds a dynamic link library (DLL) ping.dll using the Microsoft Visual C++ compiler:
cl -Ic:\java\include -Ic:\java\include\win32
-MD -LD PINGMain.c -ping.dll
Step 6: Running the PINGMain.java
java PINGMain
If you get the following error put the dll file in the java path
java.lang.UnsatisfiedLinkError: no PINGMain in library path
at java.lang.Runtime.loadLibrary(Runtime.java)
at java.lang.System.loadLibrary(System.java)
at PINGMain .main(PINGMain.java)