/*
* Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description:
*
*/
#include <stdio.h>
#include <errno.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <time.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include "logger.h"
#include "nativedatagramconnection.h"
#include "javacommonutils.h"
#include "apnsettings.h"
#include "pushexception.h"
#include "pusherrorcodes.h"
using namespace java;
using namespace java::util;
NativeDatagramConnection::NativeDatagramConnection(const char *aName,
int aMode, const char* aHost, int aPort)
{
ILOG1(ESOCKET,
"NativeDatagramConnection::NativeDatagramConnection() , host = %s",
aHost);
mName = NULL;
mHost = NULL;
mDatagramServerFactory = NULL;
mDatagramServerPtr = NULL;
mName = new char[strlen(aName) + 1];
strcpy(mName, aName);
LOG1(ESOCKET, EInfo," name = %s",aName);
mMode = aMode;
LOG1(ESOCKET, EInfo, "before , aHost + %s", aHost);
mHost = new char[strlen(aHost) + 1];
strcpy(mHost, aHost);
LOG2(ESOCKET, EInfo, "after mHost = %s , aHost + %s", mHost, aHost);
mPort = aPort;
}
int NativeDatagramConnection::openConnection(int aType, int aApn, int * err)
{
JELOG2(ESOCKET);
int ret =0;
if (strcmp(mHost, "") == 0)
{
LOG(ESOCKET, EInfo, "Datagram server connection");
mDatagramServerFactory =
&DatagramServerConnectionFactory::getFactory();
mUrl = JavaCommonUtils::utf8ToWstring((const char *) mName);
try
{
mDatagramServerPtr = reinterpret_cast<DatagramServerConnection*>(mDatagramServerFactory->create(
mUrl));
}
catch (PushException& ex)
{
LOG(ESOCKET, EInfo, "ERROR!!! CreateConnection() PushException was caught");
return -1;
}
if (mDatagramServerPtr != NULL)
{
mSockDesc = mDatagramServerPtr->open();
}
else
{
LOG(ESOCKET, EInfo, "mDatagramServerPtr is null ");
return -1;
}
}
else
{
LOG(ESOCKET, EInfo, "Datagram client connection");
mSockDesc = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_ANY);
int res = bind(mSockDesc, (struct sockaddr*) &addr, sizeof(addr));
LOG1(ESOCKET, EInfo, "Datagram client connection, bind returned %d",res);
if (aApn != -1)
{
// remove comments if open c patch available
ret = ApnSettings::setDefaultApn(aType,aApn);
}
}
LOG1(ESOCKET, EInfo, " NativeDatagramConnection::openConnection :: mSockDesc = ",mSockDesc);
*err = ret;
return mSockDesc;
}
int NativeDatagramConnection::sendDatagram(JNIEnv &aJni,
jbyteArray aJavaBuffer, int aOffset, int aLength,
const char *aDestAddr, int aDestPort)
{
JELOG2(ESOCKET);
char * writeBuffer = NULL;
int retVal;
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(aDestPort);
int requiredNativeBufferLength = aLength - aOffset;
// Allocate native buffer
if (writeBuffer == NULL)
{
writeBuffer = new char[requiredNativeBufferLength + 1];
}
/* Copy the data to be written from java buffer to the native buffer. */
JNIArrayUtils::CopyToNative(aJni, aJavaBuffer, aOffset,
requiredNativeBufferLength, writeBuffer);
if (!inet_aton(aDestAddr, &addr.sin_addr))
{
struct hostent* hp = gethostbyname(aDestAddr);
addr.sin_addr.s_addr = ((struct in_addr*)(hp->h_addr))->s_addr;
}
LOG1(ESOCKET, EInfo, "send buffer is %s", writeBuffer);
retVal = sendto(mSockDesc, writeBuffer, requiredNativeBufferLength, 0,
(struct sockaddr*) &addr, sizeof(addr));
LOG1(ESOCKET, EInfo, "number of bytes sent is %d ", retVal);
if (writeBuffer != NULL)
{
delete[] writeBuffer;
}
if (retVal < 0)
{
return -errno;
}
else
{
return retVal;
}
}
int NativeDatagramConnection::receiveDatagram(JNIEnv &aJni,
jbyteArray aJavaBuffer, int aOffset, int aLength, char* aSenderAddr,
int * aSenderPort)
{
JELOG2(ESOCKET);
char * readBuffer = NULL;
struct sockaddr_in sender_addr;
sender_addr.sin_family = AF_INET;
unsigned int size = sizeof(sender_addr);
int retVal;
int requiredNativeBufferLength = aLength - aOffset;
if (readBuffer == NULL)
{
readBuffer = new char[requiredNativeBufferLength + 2];
}
int bytesReceived = recvfrom(mSockDesc, readBuffer,
requiredNativeBufferLength, 0, (struct sockaddr*) &sender_addr,
&size);
if (bytesReceived < 0)
{
retVal = -errno;
}
else
{
retVal = bytesReceived;
strcpy(aSenderAddr, inet_ntoa(sender_addr.sin_addr));
*aSenderPort = ntohs(sender_addr.sin_port);
ILOG2(ESOCKET,
"NativeDatagramConnection::receiveDatagram() senderaddress = %s, port= %d",
aSenderAddr, aSenderPort);
JNIArrayUtils::CopyToJava(aJni, readBuffer, bytesReceived, aJavaBuffer,
aOffset, bytesReceived);
}
delete[] readBuffer;
return retVal;
}
int NativeDatagramConnection::getLocalAddress(char * aAddress)
{
JELOG2(ESOCKET);
struct sockaddr_in addr;
socklen_t len = sizeof(addr);
int retval;
LOG1(ESOCKET, EInfo,
"NativeDatagramConnection::getLocalAddress() : mSockDesc = : %d",
mSockDesc);
if (getsockname(mSockDesc, (struct sockaddr*) &addr, &len) < 0)
{
LOG1(
ESOCKET,
EInfo,
"NativeDatagramConnection::getLocalAddress() : getlocaladdress failed : %d",
errno);
strcpy(aAddress, "error");
retval = -errno;
}
else
{
strcpy(aAddress, inet_ntoa(addr.sin_addr));
retval = 0;
}
return retval;
}
int NativeDatagramConnection::getLocalPort()
{
JELOG2(ESOCKET);
struct sockaddr_in addr;
socklen_t len = sizeof(addr);
int retval;
if ((getsockname(mSockDesc, (struct sockaddr*) &addr, &len)) < 0)
{
LOG1(
ESOCKET,
EInfo,
"NativeDatagramConnection::getLocalPort() : getlocalport failed : %d",
errno);
retval = -errno;
}
else
{
retval = ntohs(addr.sin_port);
}
return retval;
}
// called only via midlet, when UDPDatagrmaConnection.close() is called
int NativeDatagramConnection::datagramClose()
{
JELOG2(ESOCKET);
int retValue;
if (strcmp(mHost, "") == 0) // server connection
{
//retValue = close(mSockDesc);
if (mUrl.length() != 12)
{
if (mDatagramServerFactory != NULL)
{
mDatagramServerFactory->releaseConnection(mUrl);
mDatagramServerFactory = NULL;
mDatagramServerPtr = NULL;
}
}
else // is it is normal server connection, then just close the socket
{
if (mDatagramServerPtr->isNormalServerConnection() == true)
{
retValue = ::close(mSockDesc);
if (retValue == -1)
{
LOG1(ESOCKET, EInfo,
"NativeDatagramConnection::datagramClose() : socket close failed : %d",
errno);
return -errno;
}
else
{
LOG1(ESOCKET, EInfo,
"NativeDatagramConnection::setsocketoption setsockopt errno %d",
-errno);
return retValue;
}
}
else // it is added to push db so call releaseconnection
{
mDatagramServerFactory->releaseConnection(mUrl);
mDatagramServerFactory = NULL;
mDatagramServerPtr = NULL;
}
}
return 0;
}
else
{
retValue = close(mSockDesc);
if (retValue == -1)
{
LOG1(ESOCKET,
EInfo,
"NativeDatagramConnection::socketClose() : socket close failed : %d",
errno);
return -errno;
}
else
{
LOG1(ESOCKET, EInfo,
"NativeDatagramConnection::setsocketoption setsockopt errno %d",
-errno);
return retValue;
}
}
}
NativeDatagramConnection::~NativeDatagramConnection()
{
JELOG2(ESOCKET);
if (mName != NULL)
{
delete[] mName;
}
if (mHost != NULL)
{
delete[] mHost;
}
}