/*
* Copyright (C) 2005 The Android Open Source Project
*
* 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.
*/
//
// Internet address class.
//
#ifdef HAVE_WINSOCK
# include <winsock2.h>
#else
# include <sys/types.h>
# include <sys/socket.h>
# include <netinet/in.h>
//# include <arpa/inet.h>
# include <netdb.h>
#endif
#include <utils/inet_address.h>
#include <utils/threads.h>
#include <utils/Log.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
using namespace android;
/*
* ===========================================================================
* InetAddress
* ===========================================================================
*/
// lock for the next couple of functions; could tuck into InetAddress
static Mutex* gGHBNLock;
/*
* Lock/unlock access to the hostent struct returned by gethostbyname().
*/
static inline void lock_gethostbyname(void)
{
if (gGHBNLock == NULL)
gGHBNLock = new Mutex;
gGHBNLock->lock();
}
static inline void unlock_gethostbyname(void)
{
assert(gGHBNLock != NULL);
gGHBNLock->unlock();
}
/*
* Constructor -- just init members. This is private so that callers
* are required to use getByName().
*/
InetAddress::InetAddress(void)
: mAddress(NULL), mLength(-1), mName(NULL)
{
}
/*
* Destructor -- free address storage.
*/
InetAddress::~InetAddress(void)
{
delete[] (char*) mAddress;
delete[] mName;
}
/*
* Copy constructor.
*/
InetAddress::InetAddress(const InetAddress& orig)
{
*this = orig; // use assignment code
}
/*
* Assignment operator.
*/
InetAddress& InetAddress::operator=(const InetAddress& addr)
{
// handle self-assignment
if (this == &addr)
return *this;
// copy mLength and mAddress
mLength = addr.mLength;
if (mLength > 0) {
mAddress = new char[mLength];
memcpy(mAddress, addr.mAddress, mLength);
LOG(LOG_DEBUG, "socket",
"HEY: copied %d bytes in assignment operator\n", mLength);
} else {
mAddress = NULL;
}
// copy mName
mName = new char[strlen(addr.mName)+1];
strcpy(mName, addr.mName);
return *this;
}
/*
* Create a new object from a name or a dotted-number IP notation.
*
* Returns NULL on failure.
*/
InetAddress*
InetAddress::getByName(const char* host)
{
InetAddress* newAddr = NULL;
struct sockaddr_in addr;
struct hostent* he;
DurationTimer hostTimer, lockTimer;
// gethostbyname() isn't reentrant, so we need to lock things until
// we can copy the data out.
lockTimer.start();
lock_gethostbyname();
hostTimer.start();
he = gethostbyname(host);
if (he == NULL) {
LOG(LOG_WARN, "socket", "WARNING: cannot resolve host %s\n", host);
unlock_gethostbyname();
return NULL;
}
memcpy(&addr.sin_addr, he->h_addr, he->h_length);
addr.sin_family = he->h_addrtype;
addr.sin_port = 0;
// got it, unlock us
hostTimer.stop();
he = NULL;
unlock_gethostbyname();
lockTimer.stop();
if ((long) lockTimer.durationUsecs() > 100000) {
long lockTime = (long) lockTimer.durationUsecs();
long hostTime = (long) hostTimer.durationUsecs();
LOG(LOG_DEBUG, "socket",
"Lookup of %s took %.3fs (gethostbyname=%.3fs lock=%.3fs)\n",
host, lockTime / 1000000.0, hostTime / 1000000.0,
(lockTime - hostTime) / 1000000.0);
}
// Alloc storage and copy it over.
newAddr = new InetAddress();
if (newAddr == NULL)
return NULL;
newAddr->mLength = sizeof(struct sockaddr_in);
newAddr->mAddress = new char[sizeof(struct sockaddr_in)];
if (newAddr->mAddress == NULL) {
delete newAddr;
return NULL;
}
memcpy(newAddr->mAddress, &addr, newAddr->mLength);
// Keep this for debug messages.
newAddr->mName = new char[strlen(host)+1];
if (newAddr->mName == NULL) {
delete newAddr;
return NULL;
}
strcpy(newAddr->mName, host);
return newAddr;
}
/*
* ===========================================================================
* InetSocketAddress
* ===========================================================================
*/
/*
* Create an address with the host wildcard (INADDR_ANY).
*/
bool InetSocketAddress::create(int port)
{
assert(mAddress == NULL);
mAddress = InetAddress::getByName("0.0.0.0");
if (mAddress == NULL)
return false;
mPort = port;
return true;
}
/*
* Create address with host and port specified.
*/
bool InetSocketAddress::create(const InetAddress* addr, int port)
{
assert(mAddress == NULL);
mAddress = new InetAddress(*addr); // make a copy
if (mAddress == NULL)
return false;
mPort = port;
return true;
}
/*
* Create address with host and port specified.
*/
bool InetSocketAddress::create(const char* host, int port)
{
assert(mAddress == NULL);
mAddress = InetAddress::getByName(host);
if (mAddress == NULL)
return false;
mPort = port;
return true;
}