353 lines
10 KiB
C++
353 lines
10 KiB
C++
/**
|
|
* Licensed to the Apache Software Foundation (ASF) under one
|
|
* or more contributor license agreements. See the NOTICE file
|
|
* distributed with this work for additional information
|
|
* regarding copyright ownership. The ASF licenses this file
|
|
* to you 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.
|
|
*/
|
|
|
|
#include <cstdlib>
|
|
#include <cstdarg>
|
|
#include <iostream>
|
|
#include <unistd.h> // needed for _POSIX_MONOTONIC_CLOCK
|
|
#include <stdarg.h>
|
|
|
|
#include "Util.h"
|
|
#include "LibCMocks.h"
|
|
|
|
#undef USING_DUMA
|
|
|
|
using namespace std;
|
|
|
|
// *****************************************************************************
|
|
// gethostbyname
|
|
|
|
struct hostent* gethostbyname(const char *name) {
|
|
if(!Mock_gethostbyname::mock_)
|
|
return LIBC_SYMBOLS.gethostbyname(name);
|
|
return Mock_gethostbyname::mock_->call(name);
|
|
}
|
|
|
|
Mock_gethostbyname* Mock_gethostbyname::mock_=0;
|
|
|
|
Mock_gethostbyname::~Mock_gethostbyname(){
|
|
mock_=0;
|
|
for(unsigned int i=0;i<gethostbynameReturns.size();i++)
|
|
delete gethostbynameReturns[i];
|
|
}
|
|
|
|
Mock_gethostbyname::HostEntry& Mock_gethostbyname::addHostEntry(
|
|
const char* hostName, short addrtype) {
|
|
gethostbynameReturns.push_back(new HostEntry(hostName, addrtype));
|
|
return *gethostbynameReturns.back();
|
|
}
|
|
|
|
hostent* Mock_gethostbyname::call(const char* name) {
|
|
assert("Must add one or more mock hostent entries first"&&
|
|
(gethostbynameReturns.size()!=0));
|
|
return gethostbynameReturns[current++ % gethostbynameReturns.size()];
|
|
}
|
|
|
|
static char** appendString(char **list,const char* str,int len=0){
|
|
const int SIZE_INCREMENT=16;
|
|
if(list==0)
|
|
list=(char**)LIBC_SYMBOLS.calloc(SIZE_INCREMENT,sizeof(char*));
|
|
// find the first available slot
|
|
int count=0;
|
|
for(char** ptr=list; *ptr!=0; ptr++,count++);
|
|
if(((count+1)%SIZE_INCREMENT)==0){
|
|
list=(char**)LIBC_SYMBOLS.realloc(list,(count+1+SIZE_INCREMENT)*sizeof(char*));
|
|
memset(list+count+1,0,SIZE_INCREMENT*sizeof(char*));
|
|
}
|
|
if(len==0){
|
|
len=strlen(str)+1;
|
|
}
|
|
char* ptr=(char*)malloc(len);
|
|
memcpy(ptr,str,len);
|
|
list[count]=ptr;
|
|
return list;
|
|
}
|
|
|
|
static void freeList(char **list){
|
|
if(list==0) return;
|
|
for(char** ptr=list; *ptr!=0; ptr++)
|
|
LIBC_SYMBOLS.free((void*)*ptr);
|
|
LIBC_SYMBOLS.free((void*)list);
|
|
}
|
|
|
|
Mock_gethostbyname::HostEntry::HostEntry(const char* hostName, short addrtype) {
|
|
h_name=strdup(hostName);
|
|
h_addrtype=addrtype;
|
|
if(addrtype==AF_INET)
|
|
h_length=4;
|
|
else{
|
|
#ifdef AF_INET6
|
|
h_length=6; // TODO: not really sure, verify!
|
|
#else
|
|
assert("AF_INET6 not supported yet"&&false);
|
|
#endif
|
|
}
|
|
h_aliases=h_addr_list=0;
|
|
}
|
|
|
|
Mock_gethostbyname::HostEntry::~HostEntry(){
|
|
if(h_name) LIBC_SYMBOLS.free((void*)h_name);
|
|
freeList(h_aliases); h_aliases=0;
|
|
freeList(h_addr_list); h_addr_list=0;
|
|
}
|
|
|
|
Mock_gethostbyname::HostEntry& Mock_gethostbyname::HostEntry::addAlias(
|
|
const char* alias) {
|
|
h_aliases=appendString(h_aliases,alias);
|
|
return *this;
|
|
}
|
|
|
|
Mock_gethostbyname::HostEntry& Mock_gethostbyname::HostEntry::addAddress(
|
|
const char* addr4) {
|
|
h_addr_list=appendString(h_addr_list,addr4,4);
|
|
return *this;
|
|
}
|
|
|
|
|
|
// *****************************************************************************
|
|
// calloc
|
|
#ifndef USING_DUMA
|
|
DECLARE_WRAPPER(void*,calloc,(size_t p1, size_t p2)){
|
|
if(!Mock_calloc::mock_)
|
|
return CALL_REAL(calloc,(p1,p2));
|
|
return Mock_calloc::mock_->call(p1,p2);
|
|
}
|
|
#endif
|
|
|
|
void* Mock_calloc::call(size_t p1, size_t p2){
|
|
#ifndef USING_DUMA
|
|
if(counter++ ==callsBeforeFailure){
|
|
counter=0;
|
|
errno=errnoOnFailure;
|
|
return 0;
|
|
}
|
|
return CALL_REAL(calloc,(p1,p2));
|
|
#else
|
|
return 0;
|
|
#endif
|
|
}
|
|
|
|
Mock_calloc* Mock_calloc::mock_=0;
|
|
|
|
// *****************************************************************************
|
|
// realloc
|
|
|
|
#ifndef USING_DUMA
|
|
DECLARE_WRAPPER(void*,realloc,(void* p, size_t s)){
|
|
if(!Mock_realloc::mock_)
|
|
return LIBC_SYMBOLS.realloc(p,s);
|
|
return Mock_realloc::mock_->call(p,s);
|
|
}
|
|
#endif
|
|
|
|
Mock_realloc* Mock_realloc::mock_=0;
|
|
|
|
void* Mock_realloc::call(void* p, size_t s){
|
|
if(counter++ ==callsBeforeFailure){
|
|
counter=0;
|
|
errno=errnoOnFailure;
|
|
return 0;
|
|
}
|
|
return LIBC_SYMBOLS.realloc(p,s);
|
|
}
|
|
|
|
// *****************************************************************************
|
|
// random
|
|
RANDOM_RET_TYPE random(){
|
|
if(!Mock_random::mock_)
|
|
return LIBC_SYMBOLS.random();
|
|
return Mock_random::mock_->call();
|
|
}
|
|
|
|
void srandom(unsigned long seed){
|
|
if (!Mock_random::mock_)
|
|
LIBC_SYMBOLS.srandom(seed);
|
|
else
|
|
Mock_random::mock_->setSeed(seed);
|
|
}
|
|
|
|
Mock_random* Mock_random::mock_=0;
|
|
|
|
int Mock_random::call(){
|
|
assert("Must specify one or more random integers"&&(randomReturns.size()!=0));
|
|
return randomReturns[currentIdx++ % randomReturns.size()];
|
|
}
|
|
|
|
// *****************************************************************************
|
|
// free
|
|
#ifndef USING_DUMA
|
|
DECLARE_WRAPPER(void,free,(void* p)){
|
|
if(Mock_free_noop::mock_ && !Mock_free_noop::mock_->nested)
|
|
Mock_free_noop::mock_->call(p);
|
|
else
|
|
CALL_REAL(free,(p));
|
|
}
|
|
#endif
|
|
|
|
void Mock_free_noop::call(void* p){
|
|
// on cygwin libc++ is linked statically
|
|
// push_back() may call free(), hence the nesting guards
|
|
synchronized(mx);
|
|
nested++;
|
|
callCounter++;
|
|
requested.push_back(p);
|
|
nested--;
|
|
}
|
|
void Mock_free_noop::freeRequested(){
|
|
#ifndef USING_DUMA
|
|
synchronized(mx);
|
|
for(unsigned i=0; i<requested.size();i++)
|
|
CALL_REAL(free,(requested[i]));
|
|
#endif
|
|
}
|
|
|
|
int Mock_free_noop::getFreeCount(void* p){
|
|
int cnt=0;
|
|
synchronized(mx);
|
|
for(unsigned i=0;i<requested.size();i++)
|
|
if(requested[i]==p)cnt++;
|
|
return cnt;
|
|
}
|
|
|
|
bool Mock_free_noop::isFreed(void* p){
|
|
synchronized(mx);
|
|
for(unsigned i=0;i<requested.size();i++)
|
|
if(requested[i]==p)return true;
|
|
return false;
|
|
}
|
|
|
|
Mock_free_noop* Mock_free_noop::mock_=0;
|
|
|
|
// *****************************************************************************
|
|
// socket
|
|
int socket(int domain, int type, int protocol){
|
|
if (!Mock_socket::mock_)
|
|
return LIBC_SYMBOLS.socket(domain,type,protocol);
|
|
return Mock_socket::mock_->callSocket(domain,type,protocol);
|
|
}
|
|
|
|
int close(int fd){
|
|
if (!Mock_socket::mock_)
|
|
return LIBC_SYMBOLS.close(fd);
|
|
return Mock_socket::mock_->callClose(fd);
|
|
}
|
|
|
|
int getsockopt(int s,int level,int optname,void *optval,socklen_t *optlen){
|
|
if (!Mock_socket::mock_)
|
|
return LIBC_SYMBOLS.getsockopt(s,level,optname,optval,optlen);
|
|
return Mock_socket::mock_->callGet(s,level,optname,optval,optlen);
|
|
}
|
|
|
|
int setsockopt(int s,int level,int optname,const void *optval,socklen_t optlen){
|
|
if (!Mock_socket::mock_)
|
|
return LIBC_SYMBOLS.setsockopt(s,level,optname,optval,optlen);
|
|
return Mock_socket::mock_->callSet(s,level,optname,optval,optlen);
|
|
}
|
|
int connect(int s,const struct sockaddr *addr,socklen_t len){
|
|
#ifdef AF_UNIX
|
|
/* don't mock UNIX domain sockets */
|
|
if (!Mock_socket::mock_ || addr->sa_family == AF_UNIX)
|
|
#else
|
|
if (!Mock_socket::mock_)
|
|
#endif
|
|
return LIBC_SYMBOLS.connect(s,addr,len);
|
|
return Mock_socket::mock_->callConnect(s,addr,len);
|
|
}
|
|
ssize_t send(int s,const void *buf,size_t len,int flags){
|
|
if (!Mock_socket::mock_)
|
|
return LIBC_SYMBOLS.send(s,buf,len,flags);
|
|
return Mock_socket::mock_->callSend(s,buf,len,flags);
|
|
}
|
|
|
|
ssize_t recv(int s,void *buf,size_t len,int flags){
|
|
if (!Mock_socket::mock_)
|
|
return LIBC_SYMBOLS.recv(s,buf,len,flags);
|
|
return Mock_socket::mock_->callRecv(s,buf,len,flags);
|
|
}
|
|
|
|
Mock_socket* Mock_socket::mock_=0;
|
|
|
|
// *****************************************************************************
|
|
// fcntl
|
|
extern "C" int fcntl(int fd,int cmd,...){
|
|
va_list va;
|
|
va_start(va,cmd);
|
|
void* arg = va_arg(va, void *);
|
|
va_end (va);
|
|
if (!Mock_fcntl::mock_)
|
|
return LIBC_SYMBOLS.fcntl(fd,cmd,arg);
|
|
return Mock_fcntl::mock_->call(fd,cmd,arg);
|
|
}
|
|
|
|
Mock_fcntl* Mock_fcntl::mock_=0;
|
|
|
|
// *****************************************************************************
|
|
// select
|
|
int select(int nfds,fd_set *rfds,fd_set *wfds,fd_set *efds,struct timeval *timeout){
|
|
if (!Mock_select::mock_)
|
|
return LIBC_SYMBOLS.select(nfds,rfds,wfds,efds,timeout);
|
|
return Mock_select::mock_->call(nfds,rfds,wfds,efds,timeout);
|
|
}
|
|
|
|
Mock_select* Mock_select::mock_=0;
|
|
|
|
// *****************************************************************************
|
|
// poll
|
|
Mock_poll* Mock_poll::mock_=0;
|
|
int poll(struct pollfd *fds, POLL_NFDS_TYPE nfds, int timeout){
|
|
if (!Mock_poll::mock_)
|
|
return LIBC_SYMBOLS.poll(fds,nfds,timeout);
|
|
return Mock_poll::mock_->call(fds,nfds,timeout);
|
|
|
|
}
|
|
|
|
/*
|
|
* Recent gcc with -O2 and glibc FORTIFY feature may cause our poll
|
|
* mock to be ignored.
|
|
*/
|
|
#if __USE_FORTIFY_LEVEL > 0
|
|
int __poll_chk (struct pollfd *__fds, nfds_t __nfds, int __timeout,
|
|
__SIZE_TYPE__ __fdslen) {
|
|
return poll(__fds, __nfds, __timeout);
|
|
}
|
|
#endif
|
|
|
|
// *****************************************************************************
|
|
// gettimeofday
|
|
int gettimeofday(struct timeval *tp, GETTIMEOFDAY_ARG2_TYPE tzp){
|
|
if (!Mock_gettimeofday::mock_)
|
|
return LIBC_SYMBOLS.gettimeofday(tp,tzp);
|
|
return Mock_gettimeofday::mock_->call(tp,tzp);
|
|
}
|
|
|
|
Mock_gettimeofday* Mock_gettimeofday::mock_=0;
|
|
|
|
// *****************************************************************************
|
|
#ifdef _POSIX_MONOTONIC_CLOCK
|
|
// clock_gettime
|
|
int clock_gettime(clockid_t id, struct timespec *tp) {
|
|
if (!Mock_gettimeofday::mock_)
|
|
return LIBC_SYMBOLS.clock_gettime(id,tp);
|
|
struct timeval tv = { 0 };
|
|
int res = Mock_gettimeofday::mock_->call(&tv, NULL);
|
|
tp->tv_sec = tv.tv_sec;
|
|
tp->tv_nsec = tv.tv_usec * 1000;
|
|
return res;
|
|
}
|
|
#endif
|