blob: df2965eaed4a3efd578e91c88b9b5c2b7c7c8a15 [file] [log] [blame]
/** @file
A brief file description
@section license License
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.
*/
/*
* This file contains all the functions exported by the IOCore to the SDK.
* Any IOCore symbol accessed by a plugin directly should be called in this
* file to ensure that it gets exported as a global symbol in TS
*/
#include "libts.h"
#include "api/ts/InkAPIPrivateIOCore.h"
#if defined(solaris) && !defined(__GNUC__)
#include "P_EventSystem.h" // I_EventSystem.h
#include "P_Net.h" // I_Net.h
#else
#include "I_EventSystem.h"
#include "I_Net.h"
#endif
#include "I_Cache.h"
#include "I_HostDB.h"
TSReturnCode
sdk_sanity_check_mutex(TSMutex mutex)
{
#ifdef DEBUG
if (mutex == NULL || mutex == TS_ERROR_PTR)
return TS_ERROR;
ProxyMutex *mutexp = (ProxyMutex *) mutex;
if (mutexp->m_refcount < 0)
return TS_ERROR;
if (mutexp->nthread_holding < 0)
return TS_ERROR;
return TS_SUCCESS;
#else
NOWARN_UNUSED(mutex);
return TS_SUCCESS;
#endif
}
TSReturnCode
sdk_sanity_check_hostlookup_structure(TSHostLookupResult data)
{
#ifdef DEBUG
if (data == NULL || data == TS_ERROR_PTR)
return TS_ERROR;
return TS_SUCCESS;
#else
NOWARN_UNUSED(data);
return TS_SUCCESS;
#endif
}
TSReturnCode
sdk_sanity_check_iocore_structure(void *data)
{
#ifdef DEBUG
if (data == NULL || data == TS_ERROR_PTR)
return TS_ERROR;
return TS_SUCCESS;
#else
NOWARN_UNUSED(data);
return TS_SUCCESS;
#endif
}
////////////////////////////////////////////////////////////////////
//
// Threads
//
////////////////////////////////////////////////////////////////////
struct INKThreadInternal:public EThread
{
#if !defined (_WIN32)
INKThreadInternal()
:EThread(DEDICATED, -1)
{
}
#endif
TSThreadFunc func;
void *data;
};
static void *
ink_thread_trampoline(void *data)
{
INKThreadInternal *thread;
void *retval;
thread = (INKThreadInternal *) data;
thread->set_specific();
retval = thread->func(thread->data);
delete thread;
return retval;
}
/*
* INKqa12653. Return TSThread or NULL if error
*/
TSThread
TSThreadCreate(TSThreadFunc func, void *data)
{
INKThreadInternal *thread;
thread = NEW(new INKThreadInternal);
#if !defined (_WIN32)
ink_assert(thread->event_types == 0);
#endif
thread->func = func;
thread->data = data;
if (!(ink_thread_create(ink_thread_trampoline, (void *) thread, 1))) {
return (TSThread) NULL;
}
return (TSThread) thread;
}
TSThread
TSThreadInit()
{
INKThreadInternal *thread;
thread = NEW(new INKThreadInternal);
#ifdef DEBUG
if (thread == NULL)
return (TSThread) NULL;
#endif
thread->set_specific();
return thread;
}
TSReturnCode
TSThreadDestroy(TSThread thread)
{
if (sdk_sanity_check_iocore_structure(thread) != TS_SUCCESS)
return TS_ERROR;
INKThreadInternal *ithread = (INKThreadInternal *) thread;
delete ithread;
return TS_SUCCESS;
}
TSThread
TSThreadSelf(void)
{
TSThread ithread = (TSThread) this_ethread();
#ifdef DEBUG
if (ithread == NULL)
return (TSThread) NULL;
#endif
return ithread;
}
////////////////////////////////////////////////////////////////////
//
// Mutexes
//
////////////////////////////////////////////////////////////////////
TSMutex
TSMutexCreate()
{
ProxyMutex *mutexp = new_ProxyMutex();
if (sdk_sanity_check_mutex((TSMutex) mutexp) != TS_SUCCESS)
return (TSMutex) TS_ERROR_PTR;
return (TSMutex) mutexp;
// return (TSMutex*) new_ProxyMutex ();
}
/* The following two APIs are for Into work, actually, APIs of Mutex
should allow plugins to manually increase or decrease the refcount
of the mutex pointer, plugins may want more control of the creation
and destroy of the mutex.*/
TSMutex
TSMutexCreateInternal()
{
ProxyMutex *new_mutex = new_ProxyMutex();
new_mutex->refcount_inc();
return (TSMutex *) new_mutex;
}
int
TSMutexCheck(TSMutex mutex)
{
ProxyMutex *mutexp = (ProxyMutex *) mutex;
if (mutexp->m_refcount < 0)
return -1;
if (mutexp->nthread_holding < 0)
return -1;
return 1;
}
TSReturnCode
TSMutexLock(TSMutex mutexp)
{
if (sdk_sanity_check_mutex(mutexp) != TS_SUCCESS)
return TS_ERROR;
MUTEX_TAKE_LOCK((ProxyMutex *) mutexp, this_ethread());
return TS_SUCCESS;
}
TSReturnCode
TSMutexLockTry(TSMutex mutexp, int *lock)
{
if (sdk_sanity_check_mutex(mutexp) != TS_SUCCESS)
return TS_ERROR;
*lock = MUTEX_TAKE_TRY_LOCK((ProxyMutex *) mutexp, this_ethread());
return TS_SUCCESS;
}
TSReturnCode
TSMutexUnlock(TSMutex mutexp)
{
if (sdk_sanity_check_mutex(mutexp) != TS_SUCCESS)
return TS_ERROR;
MUTEX_UNTAKE_LOCK((ProxyMutex *) mutexp, this_ethread());
return TS_SUCCESS;
}
/* VIOs */
TSReturnCode
TSVIOReenable(TSVIO viop)
{
if (sdk_sanity_check_iocore_structure(viop) != TS_SUCCESS)
return TS_ERROR;
VIO *vio = (VIO *) viop;
vio->reenable();
return TS_SUCCESS;
}
TSIOBuffer
TSVIOBufferGet(TSVIO viop)
{
if (sdk_sanity_check_iocore_structure(viop) != TS_SUCCESS)
return (TSIOBuffer) TS_ERROR_PTR;
VIO *vio = (VIO *) viop;
return vio->get_writer();
}
TSIOBufferReader
TSVIOReaderGet(TSVIO viop)
{
if (sdk_sanity_check_iocore_structure(viop) != TS_SUCCESS)
return (TSIOBufferReader) TS_ERROR_PTR;
VIO *vio = (VIO *) viop;
return vio->get_reader();
}
int64_t
TSVIONBytesGet(TSVIO viop)
{
if (sdk_sanity_check_iocore_structure(viop) != TS_SUCCESS)
return TS_ERROR;
VIO *vio = (VIO *) viop;
return vio->nbytes;
}
TSReturnCode
TSVIONBytesSet(TSVIO viop, int64_t nbytes)
{
if ((sdk_sanity_check_iocore_structure(viop) != TS_SUCCESS) || nbytes < 0)
return TS_ERROR;
VIO *vio = (VIO *) viop;
vio->nbytes = nbytes;
return TS_SUCCESS;
}
int64_t
TSVIONDoneGet(TSVIO viop)
{
if (sdk_sanity_check_iocore_structure(viop) != TS_SUCCESS)
return TS_ERROR;
VIO *vio = (VIO *) viop;
return vio->ndone;
}
TSReturnCode
TSVIONDoneSet(TSVIO viop, int64_t ndone)
{
if ((sdk_sanity_check_iocore_structure(viop) != TS_SUCCESS) || ndone < 0)
return TS_ERROR;
VIO *vio = (VIO *) viop;
vio->ndone = ndone;
return TS_SUCCESS;
}
int64_t
TSVIONTodoGet(TSVIO viop)
{
if (sdk_sanity_check_iocore_structure(viop) != TS_SUCCESS)
return TS_ERROR;
VIO *vio = (VIO *) viop;
return vio->ntodo();
}
TSCont
TSVIOContGet(TSVIO viop)
{
if (sdk_sanity_check_iocore_structure(viop) != TS_SUCCESS)
return (TSCont) TS_ERROR_PTR;
VIO *vio = (VIO *) viop;
return (TSCont) vio->_cont;
}
TSVConn
TSVIOVConnGet(TSVIO viop)
{
if (sdk_sanity_check_iocore_structure(viop) != TS_SUCCESS)
return (TSVConn) TS_ERROR_PTR;
VIO *vio = (VIO *) viop;
return (TSVConn) vio->vc_server;
}
TSMutex
TSVIOMutexGet(TSVIO viop)
{
if (sdk_sanity_check_iocore_structure(viop) != TS_SUCCESS)
return (TSVConn) TS_ERROR_PTR;
VIO *vio = (VIO *) viop;
return (TSMutex) ((ProxyMutex *) vio->mutex);
}
/* High Resolution Time */
ink_hrtime
INKBasedTimeGet()
{
return ink_get_based_hrtime();
}
/* UDP Connection Interface */
TSAction
INKUDPBind(TSCont contp, unsigned int ip, int port)
{
FORCE_PLUGIN_MUTEX(contp);
return (udpNet.UDPBind((Continuation *) contp, port, ip, INK_ETHERNET_MTU_SIZE, INK_ETHERNET_MTU_SIZE));
}
TSAction
INKUDPSendTo(TSCont contp, INKUDPConn udp, unsigned int ip, int port, char *data, int64_t len)
{
FORCE_PLUGIN_MUTEX(contp);
UDPPacket *packet = new_UDPPacket();
UDPConnection *conn = (UDPConnection *) udp;
packet->to.sin_family = PF_INET;
packet->to.sin_port = htons(port);
packet->to.sin_addr.s_addr = ip;
IOBufferBlock *blockp = new_IOBufferBlock();
blockp->alloc(BUFFER_SIZE_INDEX_32K);
if (len > index_to_buffer_size(BUFFER_SIZE_INDEX_32K)) {
len = index_to_buffer_size(BUFFER_SIZE_INDEX_32K) - 1;
}
memcpy(blockp->start(), data, len);
blockp->fill(len);
packet->append_block((IOBufferBlock *) blockp);
/* (Jinsheng 11/27/00) set connection twice which causes:
FATAL: ../../../proxy/iocore/UDPPacket.h:136:
failed assert `!m_conn` */
/* packet->setConnection ((UDPConnection *)udp); */
return conn->send((Continuation *) contp, packet);
}
TSAction
INKUDPRecvFrom(TSCont contp, INKUDPConn udp)
{
FORCE_PLUGIN_MUTEX(contp);
UDPConnection *conn = (UDPConnection *) udp;
return conn->recv((Continuation *) contp);
}
int
INKUDPConnFdGet(INKUDPConn udp)
{
UDPConnection *conn = (UDPConnection *) udp;
return conn->getFd();
}
/* UDP Packet */
INKUDPPacket
INKUDPPacketCreate()
{
UDPPacket *packet = new_UDPPacket();
return ((INKUDPPacket) packet);
}
TSIOBufferBlock
INKUDPPacketBufferBlockGet(INKUDPPacket packet)
{
UDPPacket *p = (UDPPacket *) packet;
return ((TSIOBufferBlock) p->getIOBlockChain());
}
unsigned int
INKUDPPacketFromAddressGet(INKUDPPacket packet)
{
UDPPacket *p = (UDPPacket *) packet;
return (p->from.sin_addr.s_addr);
}
int
INKUDPPacketFromPortGet(INKUDPPacket packet)
{
UDPPacket *p = (UDPPacket *) packet;
return (ntohs(p->from.sin_port));
}
INKUDPConn
INKUDPPacketConnGet(INKUDPPacket packet)
{
UDPPacket *p = (UDPPacket *) packet;
return ((INKUDPConn) p->getConnection());
}
void
INKUDPPacketDestroy(INKUDPPacket packet)
{
UDPPacket *p = (UDPPacket *) packet;
p->free();
}
/* Packet Queue */
INKUDPPacket
INKUDPPacketGet(INKUDPacketQueue queuep)
{
if (queuep != NULL) {
UDPPacket *packet;
Queue<UDPPacket> *qp = (Queue<UDPPacket> *)queuep;
packet = qp->pop();
return (packet);
} else
return (NULL);
}
/* Buffers */
TSIOBuffer
TSIOBufferCreate()
{
MIOBuffer *b = new_empty_MIOBuffer();
if (sdk_sanity_check_iocore_structure(b) != TS_SUCCESS) {
return (TSIOBuffer) TS_ERROR_PTR;
}
return (TSIOBuffer *) b;
}
TSIOBuffer
TSIOBufferSizedCreate(TSIOBufferSizeIndex index)
{
if ((index<TS_IOBUFFER_SIZE_INDEX_128) || (index> TS_IOBUFFER_SIZE_INDEX_32K)) {
return (TSIOBuffer) TS_ERROR_PTR;
}
MIOBuffer *b = new_MIOBuffer(index);
if (sdk_sanity_check_iocore_structure(b) != TS_SUCCESS) {
return (TSIOBuffer) TS_ERROR_PTR;
}
return (TSIOBuffer *) b;
}
TSReturnCode
TSIOBufferDestroy(TSIOBuffer bufp)
{
if (sdk_sanity_check_iocore_structure(bufp) != TS_SUCCESS)
return TS_ERROR;
free_MIOBuffer((MIOBuffer *) bufp);
return TS_SUCCESS;
}
TSIOBufferBlock
TSIOBufferStart(TSIOBuffer bufp)
{
if (sdk_sanity_check_iocore_structure(bufp) != TS_SUCCESS)
return (TSIOBufferBlock) TS_ERROR_PTR;
MIOBuffer *b = (MIOBuffer *) bufp;
IOBufferBlock *blk = b->get_current_block();
if (!blk || (blk->write_avail() == 0)) {
b->add_block();
}
blk = b->get_current_block();
// simply return error_ptr
// ink_assert (blk != NULL);
// ink_debug_assert (blk->write_avail () > 0);
#ifdef DEBUG
if (blk == NULL || (blk->write_avail() <= 0))
return (TSIOBufferBlock) TS_ERROR_PTR;
#endif
return (TSIOBufferBlock) blk;
}
TSReturnCode
TSIOBufferAppend(TSIOBuffer bufp, TSIOBufferBlock blockp)
{
if ((sdk_sanity_check_iocore_structure(bufp) != TS_SUCCESS) ||
(sdk_sanity_check_iocore_structure(blockp) != TS_SUCCESS))
return TS_ERROR;
MIOBuffer *b = (MIOBuffer *) bufp;
IOBufferBlock *blk = (IOBufferBlock *) blockp;
b->append_block(blk);
return TS_SUCCESS;
}
int64_t
TSIOBufferCopy(TSIOBuffer bufp, TSIOBufferReader readerp, int64_t length, int64_t offset)
{
if ((sdk_sanity_check_iocore_structure(bufp) != TS_SUCCESS) ||
(sdk_sanity_check_iocore_structure(readerp) != TS_SUCCESS) || length < 0 || offset < 0)
return TS_ERROR;
MIOBuffer *b = (MIOBuffer *) bufp;
IOBufferReader *r = (IOBufferReader *) readerp;
return b->write(r, length, offset);
}
int64_t
TSIOBufferWrite(TSIOBuffer bufp, const void *buf, int64_t length)
{
if ((sdk_sanity_check_iocore_structure(bufp) != TS_SUCCESS) || (buf == NULL) || (length < 0)) {
return TS_ERROR;
}
MIOBuffer *b = (MIOBuffer *) bufp;
return b->write(buf, length);
}
// not in SDK3.0
void
TSIOBufferReaderCopy(TSIOBufferReader readerp, const void *buf, int64_t length)
{
IOBufferReader *r = (IOBufferReader *) readerp;
r->memcpy(buf, length);
}
TSReturnCode
TSIOBufferProduce(TSIOBuffer bufp, int64_t nbytes)
{
if ((sdk_sanity_check_iocore_structure(bufp) != TS_SUCCESS) || nbytes < 0)
return TS_ERROR;
MIOBuffer *b = (MIOBuffer *) bufp;
b->fill(nbytes);
return TS_SUCCESS;
}
TSIOBufferData
TSIOBufferDataCreate(void *data, int64_t size, TSIOBufferDataFlags flags)
{
#ifdef DEBUG
if (data == NULL || data == TS_ERROR_PTR || size <= 0 ||
((flags != TS_DATA_ALLOCATE) && (flags != TS_DATA_MALLOCED) && (flags != TS_DATA_CONSTANT)))
return (TSIOBufferData) TS_ERROR_PTR;
#endif
// simply return error_ptr
//ink_assert (size > 0);
switch (flags) {
case TS_DATA_ALLOCATE:
ink_assert(data == NULL);
return (TSIOBufferData) new_IOBufferData(iobuffer_size_to_index(size));
case TS_DATA_MALLOCED:
ink_assert(data != NULL);
return (TSIOBufferData) new_xmalloc_IOBufferData(data, size);
case TS_DATA_CONSTANT:
ink_assert(data != NULL);
return (TSIOBufferData) new_constant_IOBufferData(data, size);
}
// simply return error_ptr
// ink_assert (!"not reached");
return (TSIOBufferData) TS_ERROR_PTR;
}
TSIOBufferBlock
TSIOBufferBlockCreate(TSIOBufferData datap, int64_t size, int64_t offset)
{
if ((sdk_sanity_check_iocore_structure(datap) != TS_SUCCESS) || size < 0 || offset < 0)
return (TSIOBufferBlock) TS_ERROR;
IOBufferData *d = (IOBufferData *) datap;
return (TSIOBufferBlock) new_IOBufferBlock(d, size, offset);
}
// dev API, not exposed
TSReturnCode
TSIOBufferBlockDestroy(TSIOBufferBlock blockp)
{
IOBufferBlock *blk = (IOBufferBlock *) blockp;
blk->free();
return TS_SUCCESS;
}
TSIOBufferBlock
TSIOBufferBlockNext(TSIOBufferBlock blockp)
{
if (sdk_sanity_check_iocore_structure(blockp) != TS_SUCCESS) {
return (TSIOBuffer) TS_ERROR_PTR;
}
IOBufferBlock *blk = (IOBufferBlock *) blockp;
return (TSIOBufferBlock) ((IOBufferBlock *) blk->next);
}
// dev API, not exposed
int64_t
TSIOBufferBlockDataSizeGet(TSIOBufferBlock blockp)
{
IOBufferBlock *blk = (IOBufferBlock *) blockp;
return (blk->read_avail());
}
const char *
TSIOBufferBlockReadStart(TSIOBufferBlock blockp, TSIOBufferReader readerp, int64_t *avail)
{
if ((sdk_sanity_check_iocore_structure(blockp) != TS_SUCCESS) ||
(sdk_sanity_check_iocore_structure(readerp) != TS_SUCCESS))
return (const char *) TS_ERROR_PTR;
IOBufferBlock *blk = (IOBufferBlock *) blockp;
IOBufferReader *reader = (IOBufferReader *) readerp;
char *p;
p = blk->start();
if (avail) {
*avail = blk->read_avail();
}
if (blk == reader->block) {
p += reader->start_offset;
if (avail) {
*avail -= reader->start_offset;
if (*avail < 0) {
*avail = 0;
}
}
}
return (const char *) p;
}
int64_t
TSIOBufferBlockReadAvail(TSIOBufferBlock blockp, TSIOBufferReader readerp)
{
if ((sdk_sanity_check_iocore_structure(blockp) != TS_SUCCESS) ||
(sdk_sanity_check_iocore_structure(readerp) != TS_SUCCESS))
return TS_ERROR;
IOBufferBlock *blk = (IOBufferBlock *) blockp;
IOBufferReader *reader = (IOBufferReader *) readerp;
int64_t avail;
avail = blk->read_avail();
if (blk == reader->block) {
avail -= reader->start_offset;
if (avail < 0) {
avail = 0;
}
}
return avail;
}
char *
TSIOBufferBlockWriteStart(TSIOBufferBlock blockp, int64_t *avail)
{
if (sdk_sanity_check_iocore_structure(blockp) != TS_SUCCESS)
return (char *) TS_ERROR_PTR;
IOBufferBlock *blk = (IOBufferBlock *) blockp;
if (avail) {
*avail = blk->write_avail();
}
return blk->end();
}
int64_t
TSIOBufferBlockWriteAvail(TSIOBufferBlock blockp)
{
if (sdk_sanity_check_iocore_structure(blockp) != TS_SUCCESS) {
return TS_ERROR;
}
IOBufferBlock *blk = (IOBufferBlock *) blockp;
return blk->write_avail();
}
TSReturnCode
TSIOBufferWaterMarkGet(TSIOBuffer bufp, int64_t *water_mark)
{
if ((sdk_sanity_check_iocore_structure(bufp) != TS_SUCCESS) || (water_mark == NULL)) {
return TS_ERROR;
}
MIOBuffer *b = (MIOBuffer *) bufp;
*water_mark = b->water_mark;
return TS_SUCCESS;
}
TSReturnCode
TSIOBufferWaterMarkSet(TSIOBuffer bufp, int64_t water_mark)
{
if ((sdk_sanity_check_iocore_structure(bufp) != TS_SUCCESS) || water_mark < 0)
return TS_ERROR;
MIOBuffer *b = (MIOBuffer *) bufp;
b->water_mark = water_mark;
return TS_SUCCESS;
}
TSIOBufferReader
TSIOBufferReaderAlloc(TSIOBuffer bufp)
{
if (sdk_sanity_check_iocore_structure(bufp) != TS_SUCCESS)
return (TSIOBufferReader) TS_ERROR_PTR;
MIOBuffer *b = (MIOBuffer *) bufp;
TSIOBufferReader readerp = (TSIOBufferReader) b->alloc_reader();
#ifdef DEBUG
if (readerp == NULL)
return (TSIOBufferReader) TS_ERROR_PTR;
#endif
return readerp;
}
TSIOBufferReader
TSIOBufferReaderClone(TSIOBufferReader readerp)
{
if (sdk_sanity_check_iocore_structure(readerp) != TS_SUCCESS)
return (TSIOBufferReader) TS_ERROR_PTR;
IOBufferReader *r = (IOBufferReader *) readerp;
return (TSIOBufferReader) r->clone();
}
TSReturnCode
TSIOBufferReaderFree(TSIOBufferReader readerp)
{
if (sdk_sanity_check_iocore_structure(readerp) != TS_SUCCESS)
return TS_ERROR;
IOBufferReader *r = (IOBufferReader *) readerp;
r->mbuf->dealloc_reader(r);
return TS_SUCCESS;
}
TSIOBufferBlock
TSIOBufferReaderStart(TSIOBufferReader readerp)
{
if (sdk_sanity_check_iocore_structure(readerp) != TS_SUCCESS)
return (TSIOBufferBlock) TS_ERROR_PTR;
IOBufferReader *r = (IOBufferReader *) readerp;
if (r->block != NULL) {
r->skip_empty_blocks();
}
return (TSIOBufferBlock) r->block;
}
TSReturnCode
TSIOBufferReaderConsume(TSIOBufferReader readerp, int64_t nbytes)
{
if ((sdk_sanity_check_iocore_structure(readerp) != TS_SUCCESS) || nbytes < 0)
return TS_ERROR;
IOBufferReader *r = (IOBufferReader *) readerp;
r->consume(nbytes);
return TS_SUCCESS;
}
int64_t
TSIOBufferReaderAvail(TSIOBufferReader readerp)
{
if (sdk_sanity_check_iocore_structure(readerp) != TS_SUCCESS)
return TS_ERROR;
IOBufferReader *r = (IOBufferReader *) readerp;
return r->read_avail();
}