| /** @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 "tscore/ink_platform.h" |
| #include "ts/ts.h" |
| #include "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" |
| |
| // This assert is for internal API use only. |
| #if TS_USE_FAST_SDK |
| #define sdk_assert(EX) (void)(EX) |
| #else |
| #define sdk_assert(EX) ((void)((EX) ? (void)0 : _TSReleaseAssert(#EX, __FILE__, __LINE__))) |
| #endif |
| |
| TSReturnCode |
| sdk_sanity_check_mutex(TSMutex mutex) |
| { |
| if (mutex == nullptr) { |
| return TS_ERROR; |
| } |
| |
| ProxyMutex *mutexp = reinterpret_cast<ProxyMutex *>(mutex); |
| |
| if (mutexp->refcount() < 0) { |
| return TS_ERROR; |
| } |
| if (mutexp->nthread_holding < 0) { |
| return TS_ERROR; |
| } |
| |
| return TS_SUCCESS; |
| } |
| |
| TSReturnCode |
| sdk_sanity_check_hostlookup_structure(TSHostLookupResult data) |
| { |
| if (data == nullptr) { |
| return TS_ERROR; |
| } |
| |
| return TS_SUCCESS; |
| } |
| |
| TSReturnCode |
| sdk_sanity_check_iocore_structure(void *data) |
| { |
| if (data == nullptr) { |
| return TS_ERROR; |
| } |
| |
| return TS_SUCCESS; |
| } |
| |
| // From InkAPI.cc |
| TSReturnCode sdk_sanity_check_continuation(TSCont cont); |
| TSReturnCode sdk_sanity_check_null_ptr(void const *ptr); |
| |
| //////////////////////////////////////////////////////////////////// |
| // |
| // Threads |
| // |
| //////////////////////////////////////////////////////////////////// |
| struct INKThreadInternal : public EThread { |
| INKThreadInternal() : EThread(DEDICATED, -1) |
| { |
| ink_mutex_init(&completion.lock); |
| ink_cond_init(&completion.signal); |
| } |
| |
| ~INKThreadInternal() override |
| { |
| ink_mutex_destroy(&completion.lock); |
| ink_cond_destroy(&completion.signal); |
| } |
| |
| TSThreadFunc func = nullptr; |
| void *data = nullptr; |
| |
| struct { |
| ink_mutex lock; |
| ink_cond signal; |
| bool done = false; |
| } completion; |
| }; |
| |
| static void * |
| ink_thread_trampoline(void *data) |
| { |
| void *retval; |
| INKThreadInternal *ithread = static_cast<INKThreadInternal *>(data); |
| |
| ithread->set_specific(); |
| retval = ithread->func(ithread->data); |
| |
| ink_mutex_acquire(&ithread->completion.lock); |
| |
| ithread->completion.done = true; |
| ink_cond_broadcast(&ithread->completion.signal); |
| |
| ink_mutex_release(&ithread->completion.lock); |
| return retval; |
| } |
| |
| /* |
| * INKqa12653. Return TSThread or NULL if error |
| */ |
| TSThread |
| TSThreadCreate(TSThreadFunc func, void *data) |
| { |
| INKThreadInternal *thread; |
| ink_thread tid = 0; |
| |
| thread = new INKThreadInternal; |
| |
| ink_assert(thread->event_types == 0); |
| ink_assert(thread->mutex->thread_holding == thread); |
| |
| thread->func = func; |
| thread->data = data; |
| |
| ink_thread_create(&tid, ink_thread_trampoline, (void *)thread, 1, 0, nullptr); |
| if (!tid) { |
| return (TSThread) nullptr; |
| } |
| |
| return reinterpret_cast<TSThread>(thread); |
| } |
| |
| // Wait for a thread to complete. When a thread calls TSThreadCreate, |
| // it becomes the owner of the thread's mutex. Since only the thread |
| // that locked a mutex should be allowed to unlock it (a condition |
| // that is enforced for PTHREAD_MUTEX_ERRORCHECK), if the application |
| // needs to delete the thread, it must first wait for the thread to |
| // complete. |
| void |
| TSThreadWait(TSThread thread) |
| { |
| sdk_assert(sdk_sanity_check_iocore_structure(thread) == TS_SUCCESS); |
| INKThreadInternal *ithread = reinterpret_cast<INKThreadInternal *>(thread); |
| |
| ink_mutex_acquire(&ithread->completion.lock); |
| |
| if (ithread->completion.done == false) { |
| ink_cond_wait(&ithread->completion.signal, &ithread->completion.lock); |
| } |
| |
| ink_mutex_release(&ithread->completion.lock); |
| } |
| |
| TSThread |
| TSThreadInit() |
| { |
| INKThreadInternal *thread; |
| |
| thread = new INKThreadInternal; |
| |
| #ifdef DEBUG |
| if (thread == nullptr) { |
| return (TSThread) nullptr; |
| } |
| #endif |
| |
| thread->set_specific(); |
| |
| return reinterpret_cast<TSThread>(thread); |
| } |
| |
| void |
| TSThreadDestroy(TSThread thread) |
| { |
| sdk_assert(sdk_sanity_check_iocore_structure(thread) == TS_SUCCESS); |
| |
| INKThreadInternal *ithread = reinterpret_cast<INKThreadInternal *>(thread); |
| |
| // The thread must be destroyed by the same thread that created |
| // it because that thread is holding the thread mutex. |
| ink_release_assert(ithread->mutex->thread_holding == ithread); |
| |
| // If this thread was created by TSThreadCreate() rather than |
| // TSThreadInit, then we must not destroy it before it's done. |
| if (ithread->func) { |
| ink_release_assert(ithread->completion.done == true); |
| } |
| |
| delete ithread; |
| } |
| |
| TSThread |
| TSThreadSelf(void) |
| { |
| TSThread ithread = (TSThread)this_ethread(); |
| return ithread; |
| } |
| |
| TSEventThread |
| TSEventThreadSelf(void) |
| { |
| return reinterpret_cast<TSEventThread>(this_event_thread()); |
| } |
| |
| //////////////////////////////////////////////////////////////////// |
| // |
| // Mutexes: For TSMutexCreate and TSMutexDestroy, the refcount of the |
| // ProxyMutex object is not incremented or decremented. If the resulting |
| // ProxyMutex is passed to a INKContInternal, it's mutex smart pointer |
| // will take ownership of the ProxyMutex and delete it when the last |
| // reference is removed. TSMutexDestroy should not be called in that case. |
| // |
| //////////////////////////////////////////////////////////////////// |
| TSMutex |
| TSMutexCreate() |
| { |
| ProxyMutex *mutexp = new_ProxyMutex(); |
| |
| // TODO: Remove this when allocations can never fail. |
| sdk_assert(sdk_sanity_check_mutex((TSMutex)mutexp) == TS_SUCCESS); |
| |
| return (TSMutex)mutexp; |
| } |
| |
| void |
| TSMutexDestroy(TSMutex m) |
| { |
| sdk_assert(sdk_sanity_check_mutex(m) == TS_SUCCESS); |
| ProxyMutex *mutexp = reinterpret_cast<ProxyMutex *>(m); |
| |
| if (mutexp) { |
| ink_release_assert(mutexp->refcount() == 0); |
| mutexp->free(); |
| } |
| } |
| |
| /* 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(); |
| |
| // TODO: Remove this when allocations can never fail. |
| sdk_assert(sdk_sanity_check_mutex((TSMutex)new_mutex) == TS_SUCCESS); |
| |
| new_mutex->refcount_inc(); |
| return reinterpret_cast<TSMutex>(new_mutex); |
| } |
| |
| int |
| TSMutexCheck(TSMutex mutex) |
| { |
| ProxyMutex *mutexp = (ProxyMutex *)mutex; |
| |
| if (mutexp->refcount() < 0) { |
| return -1; |
| } |
| if (mutexp->nthread_holding < 0) { |
| return -1; |
| } |
| return 1; |
| } |
| |
| void |
| TSMutexLock(TSMutex mutexp) |
| { |
| sdk_assert(sdk_sanity_check_mutex(mutexp) == TS_SUCCESS); |
| ProxyMutex *proxy_mutex = reinterpret_cast<ProxyMutex *>(mutexp); |
| MUTEX_TAKE_LOCK(proxy_mutex, this_ethread()); |
| } |
| |
| TSReturnCode |
| TSMutexLockTry(TSMutex mutexp) |
| { |
| sdk_assert(sdk_sanity_check_mutex(mutexp) == TS_SUCCESS); |
| ProxyMutex *proxy_mutex = reinterpret_cast<ProxyMutex *>(mutexp); |
| return (MUTEX_TAKE_TRY_LOCK(proxy_mutex, this_ethread()) ? TS_SUCCESS : TS_ERROR); |
| } |
| |
| void |
| TSMutexUnlock(TSMutex mutexp) |
| { |
| sdk_assert(sdk_sanity_check_mutex(mutexp) == TS_SUCCESS); |
| ProxyMutex *proxy_mutex(reinterpret_cast<ProxyMutex *>(mutexp)); |
| MUTEX_UNTAKE_LOCK(proxy_mutex, this_ethread()); |
| } |
| |
| /* VIOs */ |
| |
| void |
| TSVIOReenable(TSVIO viop) |
| { |
| sdk_assert(sdk_sanity_check_iocore_structure(viop) == TS_SUCCESS); |
| |
| VIO *vio = (VIO *)viop; |
| vio->reenable(); |
| } |
| |
| TSIOBuffer |
| TSVIOBufferGet(TSVIO viop) |
| { |
| sdk_assert(sdk_sanity_check_iocore_structure(viop) == TS_SUCCESS); |
| |
| VIO *vio = (VIO *)viop; |
| return reinterpret_cast<TSIOBuffer>(vio->get_writer()); |
| } |
| |
| TSIOBufferReader |
| TSVIOReaderGet(TSVIO viop) |
| { |
| sdk_assert(sdk_sanity_check_iocore_structure(viop) == TS_SUCCESS); |
| |
| VIO *vio = (VIO *)viop; |
| return reinterpret_cast<TSIOBufferReader>(vio->get_reader()); |
| } |
| |
| int64_t |
| TSVIONBytesGet(TSVIO viop) |
| { |
| sdk_assert(sdk_sanity_check_iocore_structure(viop) == TS_SUCCESS); |
| |
| VIO *vio = (VIO *)viop; |
| return vio->nbytes; |
| } |
| |
| void |
| TSVIONBytesSet(TSVIO viop, int64_t nbytes) |
| { |
| sdk_assert(sdk_sanity_check_iocore_structure(viop) == TS_SUCCESS); |
| sdk_assert(nbytes >= 0); |
| |
| VIO *vio = (VIO *)viop; |
| vio->nbytes = nbytes; |
| } |
| |
| int64_t |
| TSVIONDoneGet(TSVIO viop) |
| { |
| sdk_assert(sdk_sanity_check_iocore_structure(viop) == TS_SUCCESS); |
| |
| VIO *vio = (VIO *)viop; |
| return vio->ndone; |
| } |
| |
| void |
| TSVIONDoneSet(TSVIO viop, int64_t ndone) |
| { |
| sdk_assert(sdk_sanity_check_iocore_structure(viop) == TS_SUCCESS); |
| sdk_assert(ndone >= 0); |
| |
| VIO *vio = (VIO *)viop; |
| vio->ndone = ndone; |
| } |
| |
| int64_t |
| TSVIONTodoGet(TSVIO viop) |
| { |
| sdk_assert(sdk_sanity_check_iocore_structure(viop) == TS_SUCCESS); |
| |
| VIO *vio = (VIO *)viop; |
| return vio->ntodo(); |
| } |
| |
| TSCont |
| TSVIOContGet(TSVIO viop) |
| { |
| sdk_assert(sdk_sanity_check_iocore_structure(viop) == TS_SUCCESS); |
| |
| VIO *vio = (VIO *)viop; |
| return (TSCont)vio->cont; |
| } |
| |
| TSVConn |
| TSVIOVConnGet(TSVIO viop) |
| { |
| sdk_assert(sdk_sanity_check_iocore_structure(viop) == TS_SUCCESS); |
| |
| VIO *vio = (VIO *)viop; |
| return (TSVConn)vio->vc_server; |
| } |
| |
| TSMutex |
| TSVIOMutexGet(TSVIO viop) |
| { |
| sdk_assert(sdk_sanity_check_iocore_structure(viop) == TS_SUCCESS); |
| |
| VIO *vio = (VIO *)viop; |
| return reinterpret_cast<TSMutex>(vio->mutex.get()); |
| } |
| |
| /* High Resolution Time */ |
| |
| ink_hrtime |
| INKBasedTimeGet() |
| { |
| return Thread::get_hrtime(); |
| } |
| |
| /* UDP Connection Interface */ |
| |
| TSAction |
| INKUDPBind(TSCont contp, unsigned int ip, int port) |
| { |
| sdk_assert(sdk_sanity_check_continuation(contp) == TS_SUCCESS); |
| |
| FORCE_PLUGIN_SCOPED_MUTEX(contp); |
| |
| struct sockaddr_in addr; |
| ats_ip4_set(&addr, ip, htons(port)); |
| |
| return reinterpret_cast<TSAction>( |
| udpNet.UDPBind((Continuation *)contp, ats_ip_sa_cast(&addr), -1, INK_ETHERNET_MTU_SIZE, INK_ETHERNET_MTU_SIZE)); |
| } |
| |
| TSAction |
| INKUDPSendTo(TSCont contp, INKUDPConn udp, unsigned int ip, int port, char *data, int64_t len) |
| { |
| sdk_assert(sdk_sanity_check_continuation(contp) == TS_SUCCESS); |
| |
| FORCE_PLUGIN_SCOPED_MUTEX(contp); |
| UDPPacket *packet = new_UDPPacket(); |
| UDPConnection *conn = (UDPConnection *)udp; |
| |
| ats_ip4_set(&packet->to, ip, htons(port)); |
| |
| 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 reinterpret_cast<TSAction>(conn->send((Continuation *)contp, packet)); |
| } |
| |
| TSAction |
| INKUDPRecvFrom(TSCont contp, INKUDPConn udp) |
| { |
| sdk_assert(sdk_sanity_check_continuation(contp) == TS_SUCCESS); |
| |
| FORCE_PLUGIN_SCOPED_MUTEX(contp); |
| UDPConnection *conn = (UDPConnection *)udp; |
| return reinterpret_cast<TSAction>(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) |
| { |
| sdk_assert(sdk_sanity_check_null_ptr((void *)packet) == TS_SUCCESS); |
| |
| UDPPacket *p = (UDPPacket *)packet; |
| return ((TSIOBufferBlock)p->getIOBlockChain()); |
| } |
| |
| unsigned int |
| INKUDPPacketFromAddressGet(INKUDPPacket packet) |
| { |
| sdk_assert(sdk_sanity_check_null_ptr((void *)packet) == TS_SUCCESS); |
| |
| UDPPacket *p = (UDPPacket *)packet; |
| return ats_ip4_addr_cast(&p->from); |
| } |
| |
| int |
| INKUDPPacketFromPortGet(INKUDPPacket packet) |
| { |
| sdk_assert(sdk_sanity_check_null_ptr((void *)packet) == TS_SUCCESS); |
| |
| UDPPacket *p = (UDPPacket *)packet; |
| return ats_ip_port_host_order(&p->from); |
| } |
| |
| INKUDPConn |
| INKUDPPacketConnGet(INKUDPPacket packet) |
| { |
| sdk_assert(sdk_sanity_check_null_ptr((void *)packet) == TS_SUCCESS); |
| |
| UDPPacket *p = (UDPPacket *)packet; |
| return ((INKUDPConn)p->getConnection()); |
| } |
| |
| void |
| INKUDPPacketDestroy(INKUDPPacket packet) |
| { |
| sdk_assert(sdk_sanity_check_null_ptr((void *)packet) == TS_SUCCESS); |
| |
| UDPPacket *p = (UDPPacket *)packet; |
| p->free(); |
| } |
| |
| /* Packet Queue */ |
| |
| INKUDPPacket |
| INKUDPPacketGet(INKUDPacketQueue queuep) |
| { |
| if (queuep != nullptr) { |
| UDPPacket *packet; |
| Queue<UDPPacket> *qp = (Queue<UDPPacket> *)queuep; |
| |
| packet = qp->pop(); |
| return (packet); |
| } |
| |
| return nullptr; |
| } |
| |
| /* Buffers */ |
| |
| TSIOBuffer |
| TSIOBufferCreate() |
| { |
| MIOBuffer *b = new_empty_MIOBuffer(BUFFER_SIZE_INDEX_32K); |
| |
| // TODO: Should remove this when memory allocations can't fail. |
| sdk_assert(sdk_sanity_check_iocore_structure(b) == TS_SUCCESS); |
| return reinterpret_cast<TSIOBuffer>(b); |
| } |
| |
| TSIOBuffer |
| TSIOBufferSizedCreate(TSIOBufferSizeIndex index) |
| { |
| sdk_assert((index >= TS_IOBUFFER_SIZE_INDEX_128) && (index <= TS_IOBUFFER_SIZE_INDEX_32K)); |
| |
| MIOBuffer *b = new_MIOBuffer(index); |
| |
| // TODO: Should remove this when memory allocations can't fail. |
| sdk_assert(sdk_sanity_check_iocore_structure(b) == TS_SUCCESS); |
| return reinterpret_cast<TSIOBuffer>(b); |
| } |
| |
| void |
| TSIOBufferDestroy(TSIOBuffer bufp) |
| { |
| sdk_assert(sdk_sanity_check_iocore_structure(bufp) == TS_SUCCESS); |
| free_MIOBuffer((MIOBuffer *)bufp); |
| } |
| |
| TSIOBufferBlock |
| TSIOBufferStart(TSIOBuffer bufp) |
| { |
| sdk_assert(sdk_sanity_check_iocore_structure(bufp) == TS_SUCCESS); |
| |
| MIOBuffer *b = (MIOBuffer *)bufp; |
| IOBufferBlock *blk = b->get_current_block(); |
| |
| if (!blk || (blk->write_avail() == 0)) { |
| b->add_block(); |
| } |
| blk = b->get_current_block(); |
| |
| // TODO: Remove when memory allocations can't fail. |
| sdk_assert(sdk_sanity_check_null_ptr((void *)blk) == TS_SUCCESS); |
| |
| return (TSIOBufferBlock)blk; |
| } |
| |
| int64_t |
| TSIOBufferCopy(TSIOBuffer bufp, TSIOBufferReader readerp, int64_t length, int64_t offset) |
| { |
| sdk_assert(sdk_sanity_check_iocore_structure(bufp) == TS_SUCCESS); |
| sdk_assert(sdk_sanity_check_iocore_structure(readerp) == TS_SUCCESS); |
| sdk_assert((length >= 0) && (offset >= 0)); |
| |
| 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) |
| { |
| sdk_assert(sdk_sanity_check_iocore_structure(bufp) == TS_SUCCESS); |
| sdk_assert(sdk_sanity_check_null_ptr((void *)buf) == TS_SUCCESS); |
| sdk_assert(length >= 0); |
| |
| MIOBuffer *b = (MIOBuffer *)bufp; |
| return b->write(buf, length); |
| } |
| |
| int64_t |
| TSIOBufferReaderCopy(TSIOBufferReader readerp, void *buf, int64_t length) |
| { |
| auto r{reinterpret_cast<IOBufferReader *>(readerp)}; |
| char *limit = r->memcpy(buf, length, 0); |
| return limit - static_cast<char *>(buf); |
| } |
| |
| void |
| TSIOBufferProduce(TSIOBuffer bufp, int64_t nbytes) |
| { |
| sdk_assert(sdk_sanity_check_iocore_structure(bufp) == TS_SUCCESS); |
| sdk_assert(nbytes >= 0); |
| |
| MIOBuffer *b = (MIOBuffer *)bufp; |
| b->fill(nbytes); |
| } |
| |
| // dev API, not exposed |
| void |
| TSIOBufferBlockDestroy(TSIOBufferBlock blockp) |
| { |
| sdk_assert(sdk_sanity_check_iocore_structure(blockp) == TS_SUCCESS); |
| |
| IOBufferBlock *blk = (IOBufferBlock *)blockp; |
| blk->free(); |
| } |
| |
| TSIOBufferBlock |
| TSIOBufferBlockNext(TSIOBufferBlock blockp) |
| { |
| sdk_assert(sdk_sanity_check_iocore_structure(blockp) == TS_SUCCESS); |
| |
| IOBufferBlock *blk = (IOBufferBlock *)blockp; |
| return (TSIOBufferBlock)(blk->next.get()); |
| } |
| |
| // dev API, not exposed |
| int64_t |
| TSIOBufferBlockDataSizeGet(TSIOBufferBlock blockp) |
| { |
| sdk_assert(sdk_sanity_check_iocore_structure(blockp) == TS_SUCCESS); |
| |
| IOBufferBlock *blk = (IOBufferBlock *)blockp; |
| return (blk->read_avail()); |
| } |
| |
| const char * |
| TSIOBufferBlockReadStart(TSIOBufferBlock blockp, TSIOBufferReader readerp, int64_t *avail) |
| { |
| sdk_assert(sdk_sanity_check_iocore_structure(blockp) == TS_SUCCESS); |
| sdk_assert(sdk_sanity_check_iocore_structure(readerp) == TS_SUCCESS); |
| |
| IOBufferBlock *blk = (IOBufferBlock *)blockp; |
| IOBufferReader *reader = (IOBufferReader *)readerp; |
| char *p; |
| |
| p = blk->start(); |
| if (avail) { |
| *avail = blk->read_avail(); |
| } |
| |
| if (reader->block.get() == blk) { |
| 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) |
| { |
| sdk_assert(sdk_sanity_check_iocore_structure(blockp) == TS_SUCCESS); |
| sdk_assert(sdk_sanity_check_iocore_structure(readerp) == TS_SUCCESS); |
| |
| IOBufferBlock *blk = (IOBufferBlock *)blockp; |
| IOBufferReader *reader = (IOBufferReader *)readerp; |
| int64_t avail; |
| |
| avail = blk->read_avail(); |
| |
| if (reader->block.get() == blk) { |
| avail -= reader->start_offset; |
| if (avail < 0) { |
| avail = 0; |
| } |
| } |
| |
| return avail; |
| } |
| |
| char * |
| TSIOBufferBlockWriteStart(TSIOBufferBlock blockp, int64_t *avail) |
| { |
| sdk_assert(sdk_sanity_check_iocore_structure(blockp) == TS_SUCCESS); |
| |
| IOBufferBlock *blk = (IOBufferBlock *)blockp; |
| |
| if (avail) { |
| *avail = blk->write_avail(); |
| } |
| return blk->end(); |
| } |
| |
| int64_t |
| TSIOBufferBlockWriteAvail(TSIOBufferBlock blockp) |
| { |
| sdk_assert(sdk_sanity_check_iocore_structure(blockp) == TS_SUCCESS); |
| |
| IOBufferBlock *blk = (IOBufferBlock *)blockp; |
| return blk->write_avail(); |
| } |
| |
| int64_t |
| TSIOBufferWaterMarkGet(TSIOBuffer bufp) |
| { |
| sdk_assert(sdk_sanity_check_iocore_structure(bufp) == TS_SUCCESS); |
| |
| MIOBuffer *b = (MIOBuffer *)bufp; |
| return b->water_mark; |
| } |
| |
| void |
| TSIOBufferWaterMarkSet(TSIOBuffer bufp, int64_t water_mark) |
| { |
| sdk_assert(sdk_sanity_check_iocore_structure(bufp) == TS_SUCCESS); |
| sdk_assert(water_mark >= 0); |
| |
| MIOBuffer *b = (MIOBuffer *)bufp; |
| b->water_mark = water_mark; |
| } |
| |
| TSIOBufferReader |
| TSIOBufferReaderAlloc(TSIOBuffer bufp) |
| { |
| sdk_assert(sdk_sanity_check_iocore_structure(bufp) == TS_SUCCESS); |
| |
| MIOBuffer *b = (MIOBuffer *)bufp; |
| TSIOBufferReader readerp = (TSIOBufferReader)b->alloc_reader(); |
| |
| // TODO: Should remove this when memory allocation can't fail. |
| sdk_assert(sdk_sanity_check_null_ptr((void *)readerp) == TS_SUCCESS); |
| return readerp; |
| } |
| |
| TSIOBufferReader |
| TSIOBufferReaderClone(TSIOBufferReader readerp) |
| { |
| sdk_assert(sdk_sanity_check_iocore_structure(readerp) == TS_SUCCESS); |
| |
| IOBufferReader *r = (IOBufferReader *)readerp; |
| return (TSIOBufferReader)r->clone(); |
| } |
| |
| void |
| TSIOBufferReaderFree(TSIOBufferReader readerp) |
| { |
| sdk_assert(sdk_sanity_check_iocore_structure(readerp) == TS_SUCCESS); |
| |
| IOBufferReader *r = (IOBufferReader *)readerp; |
| r->mbuf->dealloc_reader(r); |
| } |
| |
| TSIOBufferBlock |
| TSIOBufferReaderStart(TSIOBufferReader readerp) |
| { |
| sdk_assert(sdk_sanity_check_iocore_structure(readerp) == TS_SUCCESS); |
| |
| IOBufferReader *r = (IOBufferReader *)readerp; |
| |
| if (r->block) { |
| r->skip_empty_blocks(); |
| } |
| |
| return reinterpret_cast<TSIOBufferBlock>(r->get_current_block()); |
| } |
| |
| void |
| TSIOBufferReaderConsume(TSIOBufferReader readerp, int64_t nbytes) |
| { |
| sdk_assert(sdk_sanity_check_iocore_structure(readerp) == TS_SUCCESS); |
| sdk_assert(nbytes >= 0); |
| |
| IOBufferReader *r = (IOBufferReader *)readerp; |
| r->consume(nbytes); |
| } |
| |
| int64_t |
| TSIOBufferReaderAvail(TSIOBufferReader readerp) |
| { |
| sdk_assert(sdk_sanity_check_iocore_structure(readerp) == TS_SUCCESS); |
| |
| IOBufferReader *r = (IOBufferReader *)readerp; |
| return r->read_avail(); |
| } |