237 lines
5.5 KiB
C++
237 lines
5.5 KiB
C++
|
/*
|
||
|
* 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;
|
||
|
}
|
||
|
|