Ejemplo n.º 1
0
static inline int reliable_ack___hold(su_peer_t *psar, frames_t *frame)
{
    cache_t * newack;
    newack = calloc(1, sizeof(cache_t));
    if (newack == 0) {
        errno = ENOBUFS;
        return -1;
    }
    time(&newack->ts);
    memcpy(&newack->frame, frame, sizeof(frames_t));
    newack->frame.len = -1;

    /* Adding associated */
    if (rb_insert(&psar->rbackcache, &newack->rbn) < 0) {
#if defined SU_DEBUG_LIST || defined SU_DEBUG_RBTREE 
        char ipbuff[INET6_ADDRSTRLEN];
        int port;
#ifdef SU_DEBUG_IP6FULL
        su_get_ip_port_f(&newack->frame.srcaddr, ipbuff, sizeof(ipbuff), &port);
#else
        su_get_ip_port(&newack->frame.srcaddr, ipbuff, sizeof(ipbuff), &port);
#endif
        log_msg("peer %x time %u key(%s:%d:%u:%u)"
                ColorRed " !ACK cache %p failed" ColorEnd,
                psar, newack->ts, ipbuff, port,
                newack->frame.recvhdr.sid, newack->frame.recvhdr.seq, newack);
#endif
        free(newack);
        errno = EALREADY;
        return -1;
    } else {
#if defined SU_DEBUG_LIST || defined SU_DEBUG_RBTREE
        char ipbuff[INET6_ADDRSTRLEN];
        int port;
#ifdef SU_DEBUG_IP6FULL
        su_get_ip_port_f(&newack->frame.srcaddr, ipbuff, sizeof(ipbuff), &port);
#else
        su_get_ip_port(&newack->frame.srcaddr, ipbuff, sizeof(ipbuff), &port);
#endif
        log_msg("peer %x time %u key(%s:%d:%u:%u)"
                ColorRed " !ACK cache %p" ColorEnd,
                psar, newack->ts, ipbuff, port,
                newack->frame.recvhdr.sid, newack->frame.recvhdr.seq, newack);

#endif
        list_append(&psar->lsackcache, &newack->frame.node);
    }
    return 0;
}
Ejemplo n.º 2
0
static inline void reliable_ack_unsave (su_peer_t *psar)
{
    time_t nowtime;

    cache_t *frees, *cache = container_of 
        ( list_head(&psar->lsackcache, frames_t, node), cache_t, frame );

    time(&nowtime);

    while ( &psar->lsackcache != &cache->frame.node ) {
        if ( abs(nowtime - cache->ts) < CACHETIMEOUT ) break;
        frees = cache;
        cache = container_of
            ( list_next(&cache->frame, frames_t, node), cache_t, frame );

        /* Disconnect associated */
        list_remove(&frees->frame.node);
        rb_erase(&frees->rbn, &psar->rbackcache);
#if defined SU_DEBUG_LIST || defined SU_DEBUG_RBTREE
        char ipbuff[INET6_ADDRSTRLEN];
        int port;
#ifdef SU_DEBUG_IP6FULL
        su_get_ip_port_f(&frees->frame.srcaddr, ipbuff, sizeof(ipbuff), &port);
#else
        su_get_ip_port(&frees->frame.srcaddr, ipbuff, sizeof(ipbuff), &port);
#endif
        LOG_MSG("peer %x time %u key(%s:%d:%u:%u)" ColorRed " -ACK cache %p" ColorEnd,
                psar, frees->ts, ipbuff, ntohs(port),
                frees->frame.recvhdr.sid, frees->frame.recvhdr.seq, frees);
#endif
        free(frees);
    }
}
Ejemplo n.º 3
0
void udpin_ordinary(su_peer_t *psar, char *buff, int len)
{
    SAUN saddr;
    char ip[INET6_ADDRSTRLEN];
    int port;

    su_peer_getsrcaddr(psar, &saddr);
    su_get_ip_port(&saddr, ip, sizeof(ip), &port);

    printf("ordinary recv from %s:%d datagram len %d "
            ColorGre "%s\n" ColorEnd,
            ip, port, len, buff);
}
Ejemplo n.º 4
0
static void handle_su_serv_recv(fe_t * fe)
{
    int ret;
    char ipbuff[INET6_ADDRSTRLEN];
    int  port;
    SAUN saddr;
    socklen_t socklen;
    su_serv_t *psvr = container_of(fe, su_serv_t, fe);
    struct iovec    iovrecv[2] = {{0}}; /* assumed init to 0 */
    struct msghdr   msgrecv = {0};  /* assumed init to 0 */
    frames_t *frame;
recvagain:
    socklen = sizeof(SA6);
    frame = calloc(1, sizeof(frames_t) + REALDATAMAX);
    if (frame == 0) {
        errno = ENOBUFS; // ENOMEM
        err_ret("serv %x ENOBUFS", psvr);
        /* reject datagram */
        ret = recvfrom(fe->fd, rejectbuff, sizeof(rejectbuff), 0, (SA*)&saddr, &socklen);
        if (ret < 0 && errno == EAGAIN) {
            return;
        }
#ifdef SU_DEBUG_PEER_RECV
        switch (saddr.sfamily) {
        case PF_INET:
        case PF_INET6:
#ifdef SU_DEBUG_IP6FULL
            su_get_ip_port_f(&saddr, ipbuff, sizeof(ipbuff), &port);
#else
            su_get_ip_port(&saddr, ipbuff, sizeof(ipbuff), &port);
#endif
            break;
        default:
            log_msg("serv %x reject unknown protocol raw bytes %d", psvr, ret);
            goto recvagain;
        };
        ERR_RET("serv %x %d recv %s:%d bytes %d, but reject datas", psvr,
                fe->fd, ipbuff, port, ret);
#endif
        return;
    }

    frame->srclen       = psvr->servlen;

    msgrecv.msg_name    = & frame->srcaddr;
    msgrecv.msg_namelen = frame->srclen;
    msgrecv.msg_iov     = iovrecv;
    msgrecv.msg_iovlen  = 2;

    iovrecv[0].iov_base = & frame->recvhdr;
    iovrecv[0].iov_len  = sizeof(suhdr_t);
    iovrecv[1].iov_base = frame->data;
    iovrecv[1].iov_len  = REALDATAMAX;

    if ((ret = recvmsg(fe->fd, &msgrecv, 0)) < 0) {
        if (ret < 0 && errno == EAGAIN) {
            free(frame);
            return;
        }
        ERR_RET("recvmsg error");
    }

    switch (frame->srcaddr.sfamily) {
    case PF_INET:
    case PF_INET6:
#ifdef SU_DEBUG_IP6FULL
        su_get_ip_port_f(&frame->srcaddr, ipbuff, sizeof(ipbuff), &port);
#else
        su_get_ip_port(&frame->srcaddr, ipbuff, sizeof(ipbuff), &port);
#endif
        break;
    default:
        log_msg("serv %x reject unknown protocol raw bytes %d", psvr, ret);
        free(frame);
        goto recvagain;
    };

    if (ret < sizeof(suhdr_t)) {
#ifdef SU_DEBUG_PEER_RECV
        errno = EBADMSG;
        err_ret("serv %x recv %s:%d raw bytes %d less-then head %d bytes",
                psvr, ipbuff, port, ret, sizeof(suhdr_t));
#endif
        free(frame);
        goto recvagain;
    }

#ifdef SU_DEBUG_PEER_RECV
    log_msg("serv %x recv %s:%d raw bytes %d", psvr,
            ipbuff, port, ret);
#endif

    suhdr_t *r = &frame->recvhdr;
    uint8_t act  = r->act;
    uint8_t type = r->type;

    frame->len = ret - sizeof(suhdr_t);

    pthread_mutex_lock(&psvr->lock);
    if (act == SU_SYN && frame->len > 0) {
        if (!psvr->run) {
            pthread_mutex_unlock(&psvr->lock);
            free(frame);
            goto recvagain;
        }
#if defined SU_DEBUG_PEER_RECV || defined SU_DEBUG_LIST
        log_msg("serv %x append syn "ColorRed"%p"ColorEnd" seq %d datagram len %d",
                psvr, frame, r->seq, frame->len);
#endif
        list_append(&psvr->synrecvls, &frame->node);
        pthread_cond_broadcast(&psvr->syncond);

    } else if (act == SU_ACK && type == SU_RELIABLE) {
        if (psvr->ackwaitnum <= 0) {
            pthread_mutex_unlock(&psvr->lock);
            free(frame);
            goto recvagain;
        }
#if defined SU_DEBUG_PEER_RECV || defined SU_DEBUG_LIST
        log_msg("serv %x append ack "ColorRed"%p"ColorEnd" seq %d datagram len %d",
                psvr, frame, r->seq, frame->len);
#endif
        list_append(&psvr->ackrecvls, &frame->node);
        pthread_cond_broadcast(&psvr->ackcond);

    } else {
        pthread_mutex_unlock(&psvr->lock);
#ifdef SU_DEBUG_PEER_RECV
        errno = EPROTO;
        err_ret("serv %x recv %s:%d raw bytes %d", psvr,
                ipbuff, port, ret);
#endif
        free(frame);
        return;

    }
    pthread_mutex_unlock(&psvr->lock);

    goto recvagain;
}
Ejemplo n.º 5
0
static inline int reliable_ack___save (su_peer_t *psar,
        const void *outbuff, int outbytes)
{
    /* Construct search key */
    rb_key_cache_t key;
    memcpy(&key.destaddr, & psar->nowsynframe->srcaddr, sizeof(SAUN));
    key.destlen           = psar->nowsynframe->srclen;
    key.seq               = psar->nowsynframe->recvhdr.seq;
    key.sid               = psar->nowsynframe->recvhdr.sid;

    struct rb_node *cachenode;
    cache_t *cache;

    /* If is no reply content, only replace len value, don't replace node
     * If have a content, must allocating and replacing new node */
    if (outbuff == 0 && outbytes == 0) {
        if ((cachenode = rb_search(&psar->rbackcache, &key))) {
            cache = rb_entry(cachenode, cache_t, rbn);
            cache->frame.len = 0;
#if defined SU_DEBUG_LIST || defined SU_DEBUG_RBTREE
            char ipbuff[INET6_ADDRSTRLEN];
            int port;
#ifdef SU_DEBUG_IP6FULL
            su_get_ip_port_f(&cache->frame.srcaddr, ipbuff, sizeof(ipbuff), &port);
#else
            su_get_ip_port(&cache->frame.srcaddr, ipbuff, sizeof(ipbuff), &port);
#endif
            log_msg("peer %x time %u key(%s:%d:%u:%u) "
                    ColorRed "+ACK cache %p" ColorEnd ,
                    psar, cache->ts, ipbuff, port,
                    cache->frame.recvhdr.sid, cache->frame.recvhdr.seq, cache);
#endif
            return 0;
        }
        errno = ENOKEY;
        return -1;
    }

    cache_t * newack;
    newack = calloc(1, sizeof(cache_t) + outbytes);
    if (newack == 0) {
        errno = ENOBUFS;
        return -1;
    }

    /* Construct a new node */
    memcpy(&newack->frame, psar->nowsynframe, sizeof(frames_t));
    memcpy(newack->frame.data, outbuff, outbytes);
    newack->frame.len = outbytes;

    /* Find and replace the hold node */
    if ((cachenode = rb_search(&psar->rbackcache, &key))) {
        rb_replace_node(cachenode, &newack->rbn, &psar->rbackcache);
        cache = rb_entry(cachenode, cache_t, rbn);
        newack->ts = cache->ts;
        list_remove(&cache->frame.node);
        list_append(&psar->lsackcache, &newack->frame.node);
#if defined SU_DEBUG_LIST || defined SU_DEBUG_RBTREE
        char ipbuff[INET6_ADDRSTRLEN];
        int port;
#ifdef SU_DEBUG_IP6FULL
        su_get_ip_port_f(&newack->frame.srcaddr, ipbuff, sizeof(ipbuff), &port);
#else
        su_get_ip_port(&newack->frame.srcaddr, ipbuff, sizeof(ipbuff), &port);
#endif
        log_msg("peer %x time %u key(%s:%d:%u:%u) "
                ColorRed "+ACK cache %p Swap %p" ColorEnd ,
                psar, newack->ts, ipbuff, port,
                frame->recvhdr.sid, frame->recvhdr.seq, cache, newack);
#endif
        free(cache);
        return 0;
    }
    free(newack);
    errno = ENOKEY;
    return -1;
}
Ejemplo n.º 6
0
static void handle_su_peer_recv(fe_t * fe)
{
    int ret, port;
    char ipbuff[INET6_ADDRSTRLEN];
    SAUN saddr;
    socklen_t socklen;
    su_peer_t *psar = container_of(fe, su_peer_t, fe);
    struct iovec    iovrecv[2] = {{0}}; /* assumed init to 0 */
    struct msghdr   msgrecv = {0};  /* assumed init to 0 */
    frames_t *frame;
recvagain:
    socklen = psar->destlen;
    frame = calloc(1, sizeof(frames_t) + REALDATAMAX);
    if (frame == 0) {
        errno = ENOBUFS; // ENOMEM
        log_msg("peer %x ENOBUFS", psar);
        /* reject datagram */
        ret = recvfrom(fe->fd, rejectbuff, sizeof(rejectbuff), 0, (SA*)&saddr, &socklen);
        if (ret < 0 && errno == EAGAIN) {
            return;
        }
#ifdef SU_DEBUG_PEER_RECV
        switch (saddr.sfamily) {
            case PF_INET:
            case PF_INET6:
#ifdef SU_DEBUG_IP6FULL
                su_get_ip_port_f(&saddr, ipbuff, sizeof(ipbuff), &port);
#else
                su_get_ip_port(&saddr, ipbuff, sizeof(ipbuff), &port);
#endif
                break;
            default:
                log_msg("peer %x reject unknown protocol raw bytes %d", psar, ret);
                free(frame);
                goto recvagain;
        };
        ERR_RET("peer %x recv %s:%d bytes %d, but reject datas",
                psar, ipbuff, port, ret);
#endif
        return;
    }

    frame->srclen       = psar->destlen;

    msgrecv.msg_name    = & frame->srcaddr;
    msgrecv.msg_namelen = frame->srclen;
    msgrecv.msg_iov     = iovrecv;
    msgrecv.msg_iovlen  = 2;

    iovrecv[0].iov_base = & frame->recvhdr;
    iovrecv[0].iov_len  = sizeof(suhdr_t);
    iovrecv[1].iov_base = frame->data;
    iovrecv[1].iov_len  = REALDATAMAX;

    if ((ret = recvmsg(fe->fd, &msgrecv, 0)) < 0) {
        if (ret < 0 && errno == EAGAIN) {
            free(frame);
            return;
        }
        ERR_RET("recvmsg error");
    }

    switch (frame->srcaddr.sfamily) {
        case PF_INET:
        case PF_INET6:
#ifdef SU_DEBUG_IP6FULL
            su_get_ip_port_f(&frame->srcaddr, ipbuff, sizeof(ipbuff), &port);
#else
            su_get_ip_port(&frame->srcaddr, ipbuff, sizeof(ipbuff), &port);
#endif
            break;
        default:
            log_msg("peer %x reject unknown protocol type %d raw bytes %d",
                    psar, frame->srcaddr.sfamily, ret);
            free(frame);
            goto recvagain;
    };

#ifdef SU_DEBUG_PEER_RECV
    log_msg("peer %x recv %s:%d raw bytes %d", psar, ipbuff, port, ret);
#endif

    if (ret < sizeof(suhdr_t)) {
#ifdef SU_DEBUG_PEER_RECV
        errno = EBADMSG;
        err_ret("peer %x recv %s:%d raw bytes %d less than the protocol header %d", psar,
                ipbuff, port, ret, sizeof(suhdr_t));
#endif
        free(frame);
        goto recvagain;
    }

    suhdr_t *r = &frame->recvhdr;
    uint8_t act  = r->act;
    uint8_t type = r->type;

    frame->len = ret - sizeof(suhdr_t);

    SAUN *psrc, *pdst;
    psrc = &frame->srcaddr; // foreign host
    pdst = &psar->destaddr; // localhost

#ifndef promiscuous_mode
    /*  Filter: Check address and port
     *  compare datagram source and peer destination */
    if (    (pdst->sfamily == PF_INET6 &&
                sockaddr_in6_cmp(&psrc->addr6, &pdst->addr6 ) != 0)
            || (pdst->sfamily == PF_INET &&
                sockaddr_in4_cmp(&psrc->addr4, &pdst->addr4 ) != 0)  ){
#ifdef SU_DEBUG_PEER_RECV
        log_msg(ColorYel"peer %x reject act[0x%02x] from %s:%d datagram len %d"ColorEnd,
                act, psar, ipbuff, port, frame->len);
#endif
        free(frame);
        goto recvagain;
    }
#endif /* #ifndef promiscuous_mode */

    pthread_mutex_lock(&psar->lock);
    if (act == SU_SYN && frame->len > 0) {
        if (!psar->run) {
            log_msg("peer %x thread handle no run");
            pthread_mutex_unlock(&psar->lock);
            free(frame);
            goto recvagain;
        }
#if defined SU_DEBUG_PEER_RECV || defined SU_DEBUG_LIST
        log_msg("peer %x append syn "ColorRed"%p"ColorEnd" seq %d datagram len %d",
                psar, frame, r->seq, frame->len);
#endif
        list_append(&psar->synrecvls, &frame->node);
        pthread_mutex_unlock(&psar->lock);
        pthread_cond_broadcast(&psar->syncond);
        goto recvagain;
    } else if (act == SU_ACK && type == SU_RELIABLE) {
#ifdef promiscuous_mode
        /* Filter: receive response from self request */
        if (    (pdst->sfamily == PF_INET6 &&
                    sockaddr_in6_cmp(&psrc->addr6, &pdst->addr6 ) != 0)
                || (pdst->sfamily == PF_INET &&
                    sockaddr_in4_cmp(&psrc->addr4, &pdst->addr4 ) != 0)  ){
#ifdef SU_DEBUG_PEER_RECV
            log_msg(ColorYel "peer %x reject ack from %s:%d datagram len %d" ColorEnd, psar,
                    ipbuff, port, frame->len);
#endif
            pthread_mutex_unlock(&psar->lock);
            free(frame);
            goto recvagain;
        }
#endif /* #ifdef promiscuous_mode */
        if (psar->ackwaitnum <= 0) {
            pthread_mutex_unlock(&psar->lock);
            free(frame);
            goto recvagain;
        }
#if defined SU_DEBUG_PEER_RECV || defined SU_DEBUG_LIST
        log_msg("peer %x append ack "ColorRed"%p"ColorEnd" seq %d datagram len %d",
                psar, frame, r->seq, frame->len);
#endif
        list_append(&psar->ackrecvls, &frame->node);
        pthread_mutex_unlock(&psar->lock);
        pthread_cond_broadcast(&psar->ackcond);
        goto recvagain;
    } else {
        pthread_mutex_unlock(&psar->lock);
#ifdef SU_DEBUG_PEER_RECV
        errno = EPROTO;
        err_ret("peer %x recv %s:%d raw bytes %d", psar, ipbuff, port, ret);
#endif
        free(frame);
        return;

    }
    pthread_mutex_unlock(&psar->lock);

    goto recvagain;
}
Ejemplo n.º 7
0
static void *thread_request_handle(void *v)
{
    su_peer_t *psar = (su_peer_t*)v;
    struct list *synnode;
    frames_t *frame;

    int ret;
    struct timespec abstime = {0};

    for (;psar->run;) {
        pthread_mutex_lock(&psar->lock);
        while ((synnode = psar->synrecvls.next) == &psar->synrecvls) {
            maketimeout_seconds(&abstime, 1);
            ret = pthread_cond_timedwait(&psar->syncond, &psar->lock, &abstime);
            if (!psar->run) {
                pthread_mutex_unlock(&psar->lock);
                goto quit;
            }
            if ( ret == ETIMEDOUT ) {
                pthread_mutex_lock(&psar->cachelock);
                reliable_ack_unsave(psar);
                pthread_mutex_unlock(&psar->cachelock);
            }
        }
        list_remove(synnode);
        pthread_mutex_unlock(&psar->lock);

        // TODO: Have a request
        frame = container_of(synnode, frames_t, node);

        rb_key_cache_t key;
        memcpy(&key.destaddr, &frame->srcaddr, sizeof(SAUN));
        key.destlen = frame->srclen;
        key.seq = frame->recvhdr.seq;
        key.sid = frame->recvhdr.sid;

        struct rb_node *cachenode;
        cache_t *cache;

        pthread_mutex_lock(&psar->cachelock);
        reliable_ack_unsave(psar);
        if (frame->recvhdr.type == SU_RELIABLE &&
                (cachenode = rb_search(&psar->rbackcache, &key))) {
            cache = rb_entry(cachenode, cache_t, rbn);

            if (cache->frame.len == -1) {
#ifdef SU_DEBUG_RBTREE
                char ipbuff[INET6_ADDRSTRLEN];
                int port;
#ifdef SU_DEBUG_IP6FULL
                su_get_ip_port_f(&cache->frame.srcaddr, ipbuff, sizeof(ipbuff), &port);
#else
                su_get_ip_port(&cache->frame.srcaddr, ipbuff, sizeof(ipbuff), &port);
#endif
                log_msg("peer %x time %u key(%s:%d:%u:%u)"
                        ColorRed " 0ACK cache %p" ColorEnd,
                        psvr, cache->ts, ipbuff, port,
                        cache->frame.recvhdr.sid, cache->frame.recvhdr.seq, cache);
#endif
                pthread_mutex_unlock(&psar->cachelock);
                free(frame);
                continue;
            }

#ifdef SU_DEBUG_RBTREE
            char ipbuff[INET6_ADDRSTRLEN];
            int port;
#ifdef SU_DEBUG_IP6FULL
            su_get_ip_port_f(&frame->srcaddr, ipbuff, sizeof(ipbuff), &port);
#else
            su_get_ip_port(&frame->srcaddr, ipbuff, sizeof(ipbuff), &port);
#endif
            log_msg("peer %x time %u key(%s:%d:%u:%u)" ColorRed " @ACK cache %p" ColorEnd,
                    psar,cache->ts, ipbuff, port,
                    cache->frame.recvhdr.sid,
                    cache->frame.recvhdr.seq,
                    cache);
#endif

            struct iovec	iovsend[2] = {{0}};
            struct msghdr	msgsend = {0};	/* assumed init to 0 */

            frame->recvhdr.act = SU_ACK;
            msgsend.msg_name = (void*)&cache->frame.srcaddr;
            msgsend.msg_namelen = cache->frame.srclen;
            msgsend.msg_iov = &iovsend[0];
            msgsend.msg_iovlen = 2;

            iovsend[0].iov_base = &frame->recvhdr;
            iovsend[0].iov_len = sizeof(suhdr_t);
            iovsend[1].iov_base = (void*)cache->frame.data;  /* get the cache results */
            iovsend[1].iov_len = cache->frame.len;

            if (sendmsg(psar->fd, &msgsend, 0) != sizeof(suhdr_t) + cache->frame.len) {
                char ipbuff[INET6_ADDRSTRLEN];
                int port;
#ifdef SU_DEBUG_IP6FULL
                su_get_ip_port_f(&frame->srcaddr, ipbuff, sizeof(ipbuff), &port);
#else
                su_get_ip_port(&frame->srcaddr, ipbuff, sizeof(ipbuff), &port);
#endif
                err_ret("retransmit sendmsg %s:%d:%u:%u:%u error",
                        ipbuff, port, frame->recvhdr.sid,
                        frame->recvhdr.seq, frame->recvhdr.ts);
            } 
#ifdef SU_DEBUG_PEER_RESEND
            else {
                char ipbuff[INET6_ADDRSTRLEN];
                int port;
#ifdef SU_DEBUG_IP6FULL
                su_get_ip_port_f(&frame->srcaddr, ipbuff, sizeof(ipbuff), &port);
#else
                su_get_ip_port(&frame->srcaddr, ipbuff, sizeof(ipbuff), &port);
#endif
                log_msg("retransmit sendmsg %s:%d:%u:%u:%u",
                        ipbuff, port, frame->recvhdr.sid,
                        frame->recvhdr.seq, frame->recvhdr.ts);
            }
#endif
            pthread_mutex_unlock(&psar->cachelock);
            free(frame);
            continue;
        } else {
            if (reliable_ack___hold(psar, frame) < 0) {
                err_ret("peer %x reliable_ack___hold error", psar);
                pthread_mutex_unlock(&psar->cachelock);
                free(frame);
                continue;
            }
        }

        psar->nowsynframe = frame;
        request_handle(psar);
#if defined SU_DEBUG_PEER_RECV || defined SU_DEBUG_LIST
        log_msg("peer %x delete syn "ColorRed"%p"ColorEnd" seq %d datagram len %d",
                psar, frame, frame->recvhdr.seq, frame->len);
#endif
        free(frame);
        psar->nowsynframe = 0;
        pthread_mutex_unlock(&psar->cachelock);
    }

quit:
    return (void*)0;
}