Пример #1
0
/**
 * Operator: Finalize
 */
ngemResult_t
ngrcOperatorFinalize(
    ngrcOperator_t*op)
{
    globus_result_t gResult;
    ngLog_t *log;
    ngemResult_t ret = NGEM_SUCCESS;
    NGEM_FNAME(ngrcOperatorFinalize);

    log = ngemLogGetDefault();

    NGEM_ASSERT(op != NULL);

    op->ngo_handle   = NULL;
    op->ngo_canceled = false;

    gResult = globus_mutex_destroy(&op->ngo_mutex);
    if (gResult != GLOBUS_SUCCESS) {
        ngcpLogGlobusError(log, NGRC_LOGCAT_GT, fName,
            "globus_mutex_destroy", gResult);
        ret = NGEM_FAILED;
    }
    gResult = globus_cond_destroy(&op->ngo_cond);
    if (gResult != GLOBUS_SUCCESS) {
        ngcpLogGlobusError(log, NGRC_LOGCAT_GT, fName,
            "globus_cond_destroy", gResult);
        ret = NGEM_FAILED;
    }

    return ret;
}
Пример #2
0
/**
 * Socket(Listener only): Get contact string.
 */
char *
ngrcSocketGetContactString(
    ngrcSocket_t *sock)
{
    ngLog_t *log;
    struct sockaddr_in addr; 
    char *ret = NULL;
    int result;
    ngiSockLen_t addr_len = sizeof(addr);
    NGEM_FNAME(ngrcSocketGetContactString);

    NGEM_ASSERT(sock != NULL);

    log = ngemLogGetDefault();

    /* TODO: Local socket */
    result = getsockname(sock->ngs_fd, (struct sockaddr *)&addr, &addr_len);
    if (result < 0) {
        ngLogError(log, NGRC_LOGCAT_GT, fName,
            "getsockname: %s\n", strerror(errno));
        return NULL;
    }

    NGEM_ASSERT(addr.sin_family == AF_INET);

    /* Remote Communication Proxy uses local address only. */
    ret = ngemStrdupPrintf("ng_tcp://localhost:%d/",
        ntohs(addr.sin_port));
    if (ret == NULL) {
        ngLogError(log, NGRC_LOGCAT_GT, fName,
            "Can't create address string.\n");
        return NULL;
    }
    return ret;
}
Пример #3
0
/**
 * Socket: Read
 * if nread == 0, EOF or Canceled.
 */
ngemResult_t
ngrcSocketRead(
    ngrcSocket_t *sock,
    void *buf,
    size_t size,
    size_t *nread)
{
    fd_set rfds;
    int result;
    ngLog_t *log;
    int fdmax;
    ssize_t nr = -1;
    NGEM_FNAME(ngrcSocketRead);

    NGEM_ASSERT(sock != NULL);
    NGEM_ASSERT(buf != NULL);
    NGEM_ASSERT(size > 0);
    NGEM_ASSERT(nread != NULL);

    *nread = 0;

    log = ngemLogGetDefault();

    while (nr < 0) {
        FD_ZERO(&rfds);
        FD_SET(sock->ngs_fd, &rfds);
        FD_SET(NGEM_PIPE_IN(sock->ngs_pipe), &rfds);

        fdmax = NGEM_MAX(sock->ngs_fd, NGEM_PIPE_IN(sock->ngs_pipe)) + 1;

        result = select(fdmax, &rfds, NULL, NULL, NULL);
        if (result < 0) {
            if (errno == EINTR) {
                continue;
            }
            ngLogError(log, NGRC_LOGCAT_GT, fName,
                "select: %s\n", strerror(errno));
            return NGEM_FAILED;
        }

        if (FD_ISSET(NGEM_PIPE_IN(sock->ngs_pipe), &rfds)) {
            /* Not continue */
            return NGEM_SUCCESS;
        }

        if (FD_ISSET(sock->ngs_fd, &rfds)) {
            nr = read(sock->ngs_fd, buf, size);
            if (nr < 0) {
                if (errno == EAGAIN) {continue;}
                ngLogError(log, NGRC_LOGCAT_GT, fName,
                    "read: %s\n", strerror(errno));
                return NGEM_SUCCESS;
            }
        }
    }
    *nread = nr;
    return NGEM_SUCCESS;
}
Пример #4
0
/*
 * Callback function for reading and writing
 */
static void
ngrclGlobusCallback(
    globus_xio_handle_t          handle,
    globus_result_t              cResult,
    globus_byte_t               *buffer,
    globus_size_t                len,
    globus_size_t                nbytes,
    globus_xio_data_descriptor_t dataDesc,
    void                        *userArg)
{
    ngrclOperatorCallbackArg_t *arg = userArg;
    ngrcOperator_t *op = arg->ngoca_operator;
    globus_result_t gResult;
    bool locked = false;
    ngLog_t *log = NULL;
    NGEM_FNAME(ngrclGlobusCallback);

    log = ngemLogGetDefault();
    ngLogDebug(log, NGRC_LOGCAT_GT, fName, "Called\n");

    ngLogDebug(log, NGRC_LOGCAT_GT, fName,
        "user_data = %p.\n", arg);

    gResult = globus_mutex_lock(&op->ngo_mutex);
    if (gResult != GLOBUS_SUCCESS) {
        ngcpLogGlobusError(log, NGRC_LOGCAT_GT, fName,
            "globus_mutex_lock", gResult);
    } else {
        locked = true;
    }

    ngLogDebug(log, NGRC_LOGCAT_GT, fName,
        "nBytes = %lu.\n", (unsigned long)nbytes);

    arg->ngoca_done   = true;
    arg->ngoca_result = cResult;
    arg->ngoca_bytes  = nbytes;

    gResult = globus_cond_broadcast(&op->ngo_cond);
    if (gResult != GLOBUS_SUCCESS) {
        ngcpLogGlobusError(log, NGRC_LOGCAT_GT, fName,
            "globus_cond_broadcast", gResult);
    }
    if (locked) {
        gResult = globus_mutex_unlock(&op->ngo_mutex);
        if (gResult != GLOBUS_SUCCESS) {
            ngcpLogGlobusError(log, NGRC_LOGCAT_GT, fName,
                "globus_mutex_unlock", gResult);
        }
        locked = false;
    }

    return;
}
Пример #5
0
/**
 * Socket: Destroy
 */
ngemResult_t
ngrcSocketDestroy(
    ngrcSocket_t *sock)
{
    ngemResult_t ret = NGEM_SUCCESS;
    int result;
    ngLog_t *log = NULL;
    NGEM_FNAME(ngrcSocketDestroy);

    log = ngemLogGetDefault();

    if (sock == NULL) {
        return NGEM_SUCCESS;
    }
 
    if (sock->ngs_fd >= 0) {
        result = close(sock->ngs_fd);
        if (result < 0) {
            ngLogError(log, NGRC_LOGCAT_GT, fName,
                "close: %s.\n", strerror(errno));
            ret = NGEM_FAILED;
        }
        sock->ngs_fd = -1;
    }

    if (sock->ngs_pipe[0] >= 0) {
        result = close(sock->ngs_pipe[0]);
        if (result < 0) {
            ngLogError(log, NGRC_LOGCAT_GT, fName,
                "close: %s.\n", strerror(errno));
            ret = NGEM_FAILED;
        }
        sock->ngs_pipe[0] = -1;
    }

    if (sock->ngs_pipe[1] >= 0) {
        result = close(sock->ngs_pipe[1]);
        if (result < 0) {
            ngLogError(log, NGRC_LOGCAT_GT, fName,
                "close: %s.\n", strerror(errno));
            ret = NGEM_FAILED;
        }
        sock->ngs_pipe[1] = -1;
    }

    NGI_DEALLOCATE(ngrcSocket_t, sock, log, NULL);

    return ret;
}
Пример #6
0
/**
 * Operator: cancel.
 */
ngemResult_t
ngrcOperatorCancel(
    ngrcOperator_t *op)
{
    ngLog_t *log;
    globus_result_t gResult;
    ngemResult_t ret = NGEM_SUCCESS;
    bool locked = false;
    NGEM_FNAME(ngrcOperatorCancel);

    log = ngemLogGetDefault();

    gResult = globus_mutex_lock(&op->ngo_mutex);
    if (gResult != GLOBUS_SUCCESS) {
        ngcpLogGlobusError(log, NGRC_LOGCAT_GT, fName,
            "globus_mutex_lock", gResult);
        ret = NGEM_FAILED;
    } else {
        locked = true;
    }

    op->ngo_canceled = true;
    gResult = globus_cond_broadcast(&op->ngo_cond);
    if (gResult != GLOBUS_SUCCESS) {
        ngcpLogGlobusError(log, NGRC_LOGCAT_GT, fName,
            "globus_cond_broadcast", gResult);
        ret = NGEM_FAILED;
    }
    if (locked) {
        gResult = globus_mutex_unlock(&op->ngo_mutex);
        if (gResult != GLOBUS_SUCCESS) {
            ngcpLogGlobusError(log, NGRC_LOGCAT_GT, fName,
                "globus_mutex_unlock", gResult);
            ret = NGEM_FAILED;
        }
        locked = false;
    }

    gResult = globus_xio_handle_cancel_operations(
        op->ngo_handle,
        GLOBUS_XIO_CANCEL_OPEN | GLOBUS_XIO_CANCEL_READ | GLOBUS_XIO_CANCEL_WRITE);
    if (gResult != GLOBUS_SUCCESS) {
        ngcpLogGlobusError(log, NGRC_LOGCAT_GT, fName,
            "globus_xio_handle_cancel_operations", gResult);
        ret = NGEM_FAILED;
    }

    return ret;
}
Пример #7
0
/*
 * Socket: Create(common) 
 */
static ngrcSocket_t *
ngrclSocketCreate(int fd)
{
    ngLog_t *log;
    ngemResult_t nResult;
    ngrcSocket_t *sock = NULL;
    NGEM_FNAME(ngrclSocketCreate);

    log = ngemLogGetDefault();

    sock = NGI_ALLOCATE(ngrcSocket_t, log, NULL);
    if (sock == NULL) {
        ngLogError(log, NGRC_LOGCAT_GT, fName,
            "Can't allocate the storage for socket.\n.");
        goto error;
    }
    sock->ngs_fd      = fd; 
    sock->ngs_pipe[0] = -1;
    sock->ngs_pipe[1] = -1;

    nResult = ngemFDsetNonblockFlag(sock->ngs_fd);
    if (nResult != NGEM_SUCCESS) {
        ngLogError(log, NGRC_LOGCAT_GT, fName,
            "Can't set non-block flag to fd.\n");
        goto error;
    }

    nResult = ngemNonblockingPipe(sock->ngs_pipe);
    if (nResult != NGEM_SUCCESS) {
        ngLogError(log, NGRC_LOGCAT_GT, fName,
            "Can't create the pipe.\n");
        goto error;
    }

    return sock;
error:
    nResult = ngrcSocketDestroy(sock);
    if (nResult != NGEM_SUCCESS) {
        ngLogError(log, NGRC_LOGCAT_GT, fName,
            "Can't destroy the socket.\n");
    }
    sock = NULL;
    return NULL;
}
Пример #8
0
/**
 * Operator: Initialize
 */
ngemResult_t
ngrcOperatorInitialize(
    ngrcOperator_t *op,
    globus_xio_handle_t handle)
{
    globus_result_t gResult;
    ngLog_t *log;
    bool mutexInitialized = false;
    NGEM_FNAME(ngrcOperatorInitialize);

    log = ngemLogGetDefault();

    NGEM_ASSERT(op != NULL);
    NGEM_ASSERT(handle != NULL);

    op->ngo_handle    = handle;
    op->ngo_canceled  = false;

    gResult = globus_mutex_init(&op->ngo_mutex, NULL);
    if (gResult != GLOBUS_SUCCESS) {
        ngcpLogGlobusError(log, NGRC_LOGCAT_GT, fName,
            "globus_mutex_init", gResult);
        goto error;
    }
    mutexInitialized = true;

    globus_cond_init(&op->ngo_cond, NULL);
    if (gResult != GLOBUS_SUCCESS) {
        ngcpLogGlobusError(log, NGRC_LOGCAT_GT, fName,
            "globus_cond_init", gResult);
        goto error;
    }
    return NGEM_SUCCESS;

error:
    if (mutexInitialized) {
        gResult = globus_mutex_destroy(&op->ngo_mutex);
        if (gResult != GLOBUS_SUCCESS) {
            ngcpLogGlobusError(log, NGRC_LOGCAT_GT, fName,
                "globus_mutex_destroy", gResult);
        }
    }
    return NGEM_FAILED;
}
Пример #9
0
/**
 * Socket: Cancels operation(read and write).
 */
ngemResult_t 
ngrcSocketCancel(
    ngrcSocket_t *sock)
{
    int result;
    ngLog_t *log = NULL;
    NGEM_FNAME(ngrcSocketCancel);

    log = ngemLogGetDefault();

    result = write(NGEM_PIPE_OUT(sock->ngs_pipe), "C", 1);
    if (result <= 0) {
        ngLogError(log, NGRC_LOGCAT_GT, fName,
            "write: %s\n", strerror(errno));
        return NGEM_FAILED;
    }

    return NGEM_SUCCESS;
}
Пример #10
0
/**
 * Socket: duplicate
 */
ngrcSocket_t *
ngrcSocketDup(
    ngrcSocket_t *src)
{
    ngLog_t *log;
    ngrcSocket_t *sock = NULL;
    int fd = -1;
    int result;
    NGEM_FNAME(ngrcSocketDup);

    log = ngemLogGetDefault();

    fd = dup(src->ngs_fd);
    if (fd < 0) {
        ngLogError(log, NGRC_LOGCAT_GT, fName,
            "dup: %s.\n", strerror(errno));
        goto error;
    }

    sock = ngrclSocketCreate(fd);
    if (sock == NULL) {
        ngLogError(log, NGRC_LOGCAT_GT, fName,
            "Can't create socket.\n");
        goto error;
    }

    return sock;
error:
    if (fd >= 0) {
        result = close(fd);
        if (result < 0) {
            ngLogError(log, NGRC_LOGCAT_GT, fName,
                "close: %s.\n", strerror(errno));
        }
    }

    return NULL;
}
Пример #11
0
ngemLineBuffer_t *
ngemLineBufferCreate(
    int fd,
    const char *separator)
{
    ngemLineBuffer_t *new = NULL;
    char *buffer  = NULL;
    char *copySep = NULL;
    ngLog_t *log;
    static const char fName[] = "ngemLineBufferCreate";

    NGEM_ASSERT(fd >= 0);
    NGEM_ASSERT(NGEM_STRING_IS_NONZERO(separator));

    log = ngemLogGetDefault();

    new = NGI_ALLOCATE(ngemLineBuffer_t, log, NULL);
    if (new == NULL) {
        ngLogError(log, NGEM_LOGCAT_CALLBACK, fName, 
            "Can't allocate storage for line buffer.\n");
        goto error;
    }

    buffer = ngiMalloc(NGEML_LINE_BUFFER_INITIAL_SIZE, log, NULL);
    if (buffer == NULL) {
        ngLogError(log, NGEM_LOGCAT_CALLBACK, fName,
            "Can't allocate storage for buffer.\n");
        goto error;
    }
    buffer[0] = '\0';
Пример #12
0
/**
 * Socket: Create listener.
 */
ngrcSocket_t *
ngrcSocketCreateListener(
    bool tcpNodelay)
{
    ngLog_t *log;
    int result;
    int fd = -1;
    struct sockaddr_in addr; 
    ngrcSocket_t *sock = NULL;
    int nodelay;
    NGEM_FNAME(ngrcSocketCreateListener);

    log = ngemLogGetDefault();

    /* TODO: Local socket */
    fd = socket(PF_INET, SOCK_STREAM, 0);
    if (fd < 0) {
        ngLogError(log, NGRC_LOGCAT_GT, fName,
            "socket: %s.\n", strerror(errno));
        goto error;
    }
    memset(&addr, '\0', sizeof(addr));
    addr.sin_family      = AF_INET;
    addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
    addr.sin_port        = htons(0); /* any */

    result = bind(fd, (struct sockaddr *)&addr, sizeof(addr));
    if (result < 0) {
        ngLogError(log, NGRC_LOGCAT_GT, fName,
            "bind: %s.\n", strerror(errno));
        goto error;
    }

    if (tcpNodelay) {
        nodelay = 1;
        result = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &nodelay, sizeof(nodelay));
        if (result < 0) {
            ngLogError(log, NGRC_LOGCAT_GT, fName,
                "setsockopt(TCP_NODELAY): %s.\n", strerror(errno));
            goto error;
        }
    }

    /* backlog is 1 because Remote Communication Proxy handles
     * a connection only.*/
    result = listen(fd, 1);
    if (result < 0) {
        ngLogError(log, NGRC_LOGCAT_GT, fName,
            "listen: %s.\n", strerror(errno));
        goto error;
    }

    sock = ngrclSocketCreate(fd);
    if (sock == NULL) {
        ngLogError(log, NGRC_LOGCAT_GT, fName,
            "Can't create socket.\n");
        goto error;
    }

    return sock;
error:
    if (fd >= 0) {
        result = close(fd);
        if (result < 0) {
            ngLogError(log, NGRC_LOGCAT_GT, fName,
                "close: %s.\n", strerror(errno));
        }
    }

    return NULL;
}
Пример #13
0
/**
 * Socket:Write 
 * if nwrite < size, Canceled.
 */
ngemResult_t
ngrcSocketWrite(
    ngrcSocket_t *sock,
    void *buf,
    size_t size,
    size_t *nwrite)
{
    fd_set rfds;
    fd_set wfds;
    int result;
    ngLog_t *log;
    int fdmax;
    ssize_t nw = 0;
    size_t sum = 0;
    NGEM_FNAME(ngrcSocketWrite);

    NGEM_ASSERT(sock != NULL);
    NGEM_ASSERT(buf != NULL);
    NGEM_ASSERT(size > 0);
    NGEM_ASSERT(nwrite != NULL);

    *nwrite = 0;

    log = ngemLogGetDefault();

    while (sum < size) {
        FD_ZERO(&rfds);
        FD_ZERO(&wfds);
        FD_SET(sock->ngs_fd, &wfds);
        FD_SET(NGEM_PIPE_IN(sock->ngs_pipe), &rfds);

        fdmax = NGEM_MAX(sock->ngs_fd, NGEM_PIPE_IN(sock->ngs_pipe)) + 1;

        result = select(fdmax, &rfds, &wfds, NULL, NULL);
        if (result < 0) {
            if (errno == EINTR) {
                continue;
            }
            ngLogError(log, NGRC_LOGCAT_GT, fName,
                "select: %s\n", strerror(errno));
            return NGEM_FAILED;
        }

        if (FD_ISSET(NGEM_PIPE_IN(sock->ngs_pipe), &rfds)) {
            /* Not continue */
            *nwrite = sum;
            return NGEM_SUCCESS;
        }

        if (FD_ISSET(sock->ngs_fd, &wfds)) {
            nw = write(sock->ngs_fd, ((char *)buf)+sum, size-sum);
            if (nw < 0) {
                if (errno == EAGAIN) {continue;}
                ngLogError(log, NGRC_LOGCAT_GT, fName,
                    "write: %s\n", strerror(errno));
                return NGEM_FAILED;
            }
            sum += nw;
            NGEM_ASSERT(sum <= size);
        }
    }
    *nwrite = sum;

    return NGEM_SUCCESS;
}
Пример #14
0
/**
 * Socket: accept
 */
ngrcSocket_t *
ngrcSocketAccept(
    ngrcSocket_t *listener,
    bool *canceled)
{
    ngrcSocket_t *sock = NULL;
    int fd = -1;
    fd_set rfds;
    int result;
    ngLog_t *log;
    int fdmax;
    struct sockaddr_in addr; 
    ngiSockLen_t addr_len = sizeof(addr);
    NGEM_FNAME(ngrcSocketAccept);

    NGEM_ASSERT(listener != NULL);
    NGEM_ASSERT(canceled != NULL);

    *canceled = false;

    log = ngemLogGetDefault();

    while (fd < 0) {
        FD_ZERO(&rfds);
        FD_SET(listener->ngs_fd, &rfds);
        FD_SET(NGEM_PIPE_IN(listener->ngs_pipe), &rfds);

        fdmax = NGEM_MAX(listener->ngs_fd, NGEM_PIPE_IN(listener->ngs_pipe)) + 1;

        result = select(fdmax, &rfds, NULL, NULL, NULL);
        if (result < 0) {
            if (errno == EINTR) {
                continue;
            }
            ngLogError(log, NGRC_LOGCAT_GT, fName,
                "select: %s\n", strerror(errno));
            goto error;
        }

        if (FD_ISSET(NGEM_PIPE_IN(listener->ngs_pipe), &rfds)) {
            /* Not continue */
            *canceled = true;
            return NULL;
        }

        if (FD_ISSET(listener->ngs_fd, &rfds)) {
            fd = accept(listener->ngs_fd, (struct sockaddr *)&addr, &addr_len);
            if (result < 0) {
                if (errno == EAGAIN) {continue;}
                ngLogError(log, NGRC_LOGCAT_GT, fName,
                    "accept: %s\n", strerror(errno));
                if (errno == EBADF) {
                    return NULL;
                }
                continue;
            }
        }
    }

    sock = ngrclSocketCreate(fd);
    if (sock == NULL) {
        ngLogError(log, NGRC_LOGCAT_GT, fName,
            "Can't create socket.\n");
        goto error;
    }

    return sock;
error:
    if (fd >= 0) {
        result = close(fd);
        if (result < 0) {
            ngLogError(log, NGRC_LOGCAT_GT, fName,
                "close: %s.\n", strerror(errno));
        }
    }

    return NULL;
}
Пример #15
0
/**
 * Operator: write
 */
ngemResult_t
ngrcOperatorWrite(
    ngrcOperator_t *op,
    void *buf,
    size_t size,
    size_t *nWrite,
    bool *canceled)
{
    globus_result_t gResult;
    ngemResult_t ret = NGEM_FAILED;
    bool locked = false;
    ngLog_t *log = NULL;
    ngrclOperatorCallbackArg_t arg;
    NGEM_FNAME(ngrcOperatorWrite);

    log = ngemLogGetDefault();

    NGEM_ASSERT(op != NULL);
    NGEM_ASSERT(size >= 0);
    NGEM_ASSERT(nWrite != NULL);
    NGEM_ASSERT(canceled != NULL);

    *canceled = false;

    gResult = globus_mutex_lock(&op->ngo_mutex);
    if (gResult != GLOBUS_SUCCESS) {
        ngcpLogGlobusError(log, NGRC_LOGCAT_GT, fName,
            "globus_mutex_lock", gResult);
        goto finalize;
    } 
    locked = true;

    ngrclOperatorCallbackArgInitialize(&arg, op);

    if (op->ngo_canceled) {
        *canceled = true;
    } else {

        ngLogDebug(log, NGRC_LOGCAT_GT, fName,
            "user_data = %p.\n", &arg);

        gResult = globus_xio_register_write(
            op->ngo_handle, buf, size, size, NULL,
            ngrclGlobusCallback, &arg);
        if (gResult != GLOBUS_SUCCESS) {
            ngcpLogGlobusError(log, NGRC_LOGCAT_GT, fName,
                "globus_xio_register_write", gResult);
            goto finalize;
        }

        while (arg.ngoca_done == false) {
            gResult = globus_cond_wait(&op->ngo_cond, &op->ngo_mutex);
            if (gResult != GLOBUS_SUCCESS) {
                ngcpLogGlobusError(log, NGRC_LOGCAT_GT, fName,
                    "globus_cond_wait", gResult);
            }
        }

        if (arg.ngoca_result != GLOBUS_SUCCESS) {
            if (globus_xio_error_is_canceled(arg.ngoca_result) == GLOBUS_FALSE) {
                ngcpLogGlobusError(log, NGRC_LOGCAT_GT, fName,
                    "Callback function for writing", arg.ngoca_result);
                goto finalize;
            }
            *canceled = true;
        } else {
            ngLogDebug(log, NGRC_LOGCAT_GT, fName,
                "Writes %lu bytes\n", (unsigned long)arg.ngoca_bytes);
            *nWrite = arg.ngoca_bytes;
        }
    }

    ret = NGEM_SUCCESS;

finalize:
    ngrclOperatorCallbackArgFinalize(&arg);

    if (locked) {
        gResult = globus_mutex_unlock(&op->ngo_mutex);
        if (gResult != GLOBUS_SUCCESS) {
            ngcpLogGlobusError(log, NGRC_LOGCAT_GT, fName,
                "globus_mutex_unlock", gResult);
            ret = NGEM_FAILED;
        }
        locked = false;
    }

    return ret;
}
Пример #16
0
/**
 * Operator: read
 */
ngemResult_t
ngrcOperatorRead(
    ngrcOperator_t *op,
    void *buf,
    size_t size,
    size_t *nRead,
    bool *canceled)
{
    ngemResult_t ret = NGEM_FAILED;
    globus_result_t gResult;
    ngLog_t *log = NULL;
    bool locked = false;
    ngrclOperatorCallbackArg_t arg;
    NGEM_FNAME(ngrcOperatorRead);

    log = ngemLogGetDefault();

    NGEM_ASSERT(op != NULL);
    NGEM_ASSERT(size >= 0);
    NGEM_ASSERT(nRead != NULL);
    NGEM_ASSERT(canceled != NULL);

    *canceled = false;

    gResult = globus_mutex_lock(&op->ngo_mutex);
    if (gResult != GLOBUS_SUCCESS) {
        ngcpLogGlobusError(log, NGRC_LOGCAT_GT, fName,
            "globus_mutex_lock", gResult);
        goto finalize;
    } 
    locked = true;

    ngrclOperatorCallbackArgInitialize(&arg, op);

    if (op->ngo_canceled) {
        *canceled = true;
        ret = NGEM_SUCCESS;
        goto finalize;
    }

    gResult = globus_xio_register_read(
        op->ngo_handle, buf, size, 1, NULL,
        ngrclGlobusCallback, &arg);
    if (gResult != GLOBUS_SUCCESS) {
        ngcpLogGlobusError(log, NGRC_LOGCAT_GT, fName,
            "globus_xio_register_read", gResult);
        goto finalize;
    }

    while (arg.ngoca_done == false) {
        gResult = globus_cond_wait(&op->ngo_cond, &op->ngo_mutex);
        if (gResult != GLOBUS_SUCCESS) {
            ngcpLogGlobusError(log, NGRC_LOGCAT_GT, fName,
                "globus_cond_wait", gResult);
        }
    }

    if (arg.ngoca_result != GLOBUS_SUCCESS) {
        if (globus_xio_error_is_canceled(arg.ngoca_result) == GLOBUS_TRUE) {
            *canceled = true;
        } else if (globus_xio_error_is_eof(arg.ngoca_result) == GLOBUS_TRUE) {
            *nRead = 0;
        } else {
            ngcpLogGlobusError(log, NGRC_LOGCAT_GT, fName,
                "Callback function for reading", arg.ngoca_result);
            goto finalize;
        }
    } else {
        *nRead = arg.ngoca_bytes;
        NGEM_ASSERT(*nRead > 0);
    }

    ret = NGEM_SUCCESS;
finalize:
    ngrclOperatorCallbackArgFinalize(&arg);

    if (locked) {
        gResult = globus_mutex_unlock(&op->ngo_mutex);
        if (gResult != GLOBUS_SUCCESS) {
            ngcpLogGlobusError(log, NGRC_LOGCAT_GT, fName,
                "globus_mutex_unlock", gResult);
            ret = NGEM_FAILED;
        }
        locked = false;
    }

    return ret;
}