209 lines
5.2 KiB
C
209 lines
5.2 KiB
C
|
/****************************************************************
|
||
|
* *
|
||
|
* Copyright 2001, 2009 Fidelity Information Services, Inc *
|
||
|
* *
|
||
|
* This source code contains the intellectual property *
|
||
|
* of its copyright holder(s), and is made available *
|
||
|
* under a license. If you do not know the terms of *
|
||
|
* the license, please stop and do not read further. *
|
||
|
* *
|
||
|
****************************************************************/
|
||
|
|
||
|
#include "mdef.h"
|
||
|
#include "gtm_socket.h"
|
||
|
#include "gtm_string.h"
|
||
|
#include "cmidef.h"
|
||
|
#include <errno.h>
|
||
|
#include <sys/uio.h>
|
||
|
#include "gtm_inet.h"
|
||
|
|
||
|
#define NUM_IOVECS 2
|
||
|
#define NUM_IOVECS_BOTH 2
|
||
|
#define NUM_IOVECS_DATA 1
|
||
|
|
||
|
cmi_status_t cmj_read_start(struct CLB *lnk)
|
||
|
{
|
||
|
struct NTD *tsk = lnk->ntd;
|
||
|
cmi_status_t status = SS_NORMAL;
|
||
|
int save_errno;
|
||
|
ssize_t rval;
|
||
|
error_def(CMI_DCNINPROG);
|
||
|
error_def(CMI_LNKNOTIDLE);
|
||
|
error_def(CMI_OVERRUN);
|
||
|
|
||
|
if (-1 == lnk->mun)
|
||
|
return ENOTCONN;
|
||
|
if (CM_CLB_IDLE != lnk->sta)
|
||
|
return (CM_CLB_DISCONNECT == lnk->sta) ? CMI_DCNINPROG : CMI_LNKNOTIDLE;
|
||
|
lnk->sta = CM_CLB_READ;
|
||
|
CMI_CLB_IOSTATUS(lnk) = SS_NORMAL;
|
||
|
lnk->ios.xfer_count = 0;
|
||
|
lnk->ios.len_len = 0;
|
||
|
|
||
|
while ((-1 == (rval = recv(lnk->mun, (void *)lnk->ios.u.lenbuf, CMI_TCP_PREFIX_LEN, 0))) && EINTR == errno)
|
||
|
;
|
||
|
/*
|
||
|
* rval == 0 --> eof
|
||
|
* rval == 2 --> entire length read (2 == CMI_TCP_PREFIX_LEN)
|
||
|
* rval == 1 || (rval < 0 && (errno == EWOULDBLOCK || errno == EAGAIN) --> read stream empty
|
||
|
*/
|
||
|
/* weed out the bad things first */
|
||
|
if (0 > rval && !CMI_IO_WOULDBLOCK(errno))
|
||
|
{
|
||
|
save_errno = errno;
|
||
|
cmj_err(lnk, CMI_REASON_STATUS, save_errno);
|
||
|
cmj_postevent(lnk);
|
||
|
return save_errno;
|
||
|
}
|
||
|
if (0 == rval)
|
||
|
{
|
||
|
cmj_err(lnk, CMI_REASON_STATUS, ECONNRESET);
|
||
|
cmj_postevent(lnk);
|
||
|
return ECONNRESET;
|
||
|
}
|
||
|
if (CMI_TCP_PREFIX_LEN == rval)
|
||
|
{
|
||
|
/* got the entire length */
|
||
|
lnk->ios.len_len = CMI_TCP_PREFIX_LEN;
|
||
|
lnk->ios.u.len = ntohs(lnk->ios.u.len);
|
||
|
if (lnk->ios.u.len > lnk->mbl)
|
||
|
return CMI_OVERRUN;
|
||
|
|
||
|
while ((-1 == (rval = recv(lnk->mun, (void *)lnk->mbf, (int)lnk->ios.u.len, 0))) && EINTR == errno)
|
||
|
;
|
||
|
if (0 > rval && !CMI_IO_WOULDBLOCK(errno))
|
||
|
{
|
||
|
save_errno = errno;
|
||
|
cmj_err(lnk, CMI_REASON_STATUS, save_errno);
|
||
|
cmj_postevent(lnk);
|
||
|
return save_errno;
|
||
|
}
|
||
|
if (0 == rval)
|
||
|
{
|
||
|
cmj_err(lnk, CMI_REASON_STATUS, ECONNRESET);
|
||
|
cmj_postevent(lnk);
|
||
|
return ECONNRESET;
|
||
|
}
|
||
|
if (rval == lnk->ios.u.len)
|
||
|
{
|
||
|
lnk->ios.xfer_count = rval;
|
||
|
cmj_fini(lnk);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/* partial read or no read of packet */
|
||
|
if (0 < rval)
|
||
|
lnk->ios.xfer_count = rval;
|
||
|
status = cmj_clb_set_async(lnk);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/* partial or no read of length */
|
||
|
if (0 < rval)
|
||
|
{
|
||
|
assert(CMI_TCP_PREFIX_LEN > rval);
|
||
|
lnk->ios.len_len = (int)rval;
|
||
|
}
|
||
|
status = cmj_clb_set_async(lnk);
|
||
|
}
|
||
|
return status;
|
||
|
}
|
||
|
|
||
|
void cmj_read_interrupt(struct CLB *lnk, int signo)
|
||
|
{
|
||
|
ssize_t rval;
|
||
|
cmi_status_t status = SS_NORMAL;
|
||
|
error_def(CMI_OVERRUN);
|
||
|
char peekchar;
|
||
|
struct iovec vec[NUM_IOVECS];
|
||
|
struct msghdr msg;
|
||
|
|
||
|
if (-1 == lnk->mun)
|
||
|
return;
|
||
|
if (CM_CLB_IDLE == lnk->sta)
|
||
|
{
|
||
|
/* potential eof, error */
|
||
|
/* just peek to see if a 0 or error comes back */
|
||
|
while ((-1 == (rval = recv(lnk->mun, (void *)&peekchar, 1, MSG_PEEK))) && EINTR == errno)
|
||
|
;
|
||
|
if (0 == rval)
|
||
|
cmj_err(lnk, CMI_REASON_STATUS, (cmi_status_t)ECONNRESET);
|
||
|
else
|
||
|
{
|
||
|
if (-1 == rval && !CMI_IO_WOULDBLOCK(errno))
|
||
|
cmj_err(lnk, CMI_REASON_STATUS, (cmi_status_t)errno);
|
||
|
}
|
||
|
/* no I/O outstand - return leaving data in socket */
|
||
|
return;
|
||
|
}
|
||
|
/* setup I/O vec based on past history */
|
||
|
memset(&msg, 0, SIZEOF(msg));
|
||
|
msg.msg_iov = vec;
|
||
|
if (CMI_TCP_PREFIX_LEN > lnk->ios.len_len)
|
||
|
{
|
||
|
/* length not entirely read */
|
||
|
msg.msg_iovlen = NUM_IOVECS_BOTH;
|
||
|
vec[0].iov_len = CMI_TCP_PREFIX_LEN - lnk->ios.len_len;
|
||
|
vec[0].iov_base = (lnk->ios.u.lenbuf + lnk->ios.len_len);
|
||
|
vec[1].iov_len = lnk->mbl;
|
||
|
vec[1].iov_base = (caddr_t)lnk->mbf;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/* length had been read, need to complete data */
|
||
|
msg.msg_iovlen = NUM_IOVECS_DATA;
|
||
|
vec[0].iov_len = lnk->ios.u.len - lnk->ios.xfer_count;
|
||
|
vec[0].iov_base = (caddr_t)(lnk->mbf + lnk->ios.xfer_count);
|
||
|
}
|
||
|
|
||
|
while ((-1 == (rval = recvmsg(lnk->mun, &msg, 0))) && EINTR == errno)
|
||
|
;
|
||
|
/* weed out the bad things first */
|
||
|
if (0 == rval)
|
||
|
{
|
||
|
cmj_err(lnk, CMI_REASON_STATUS, (cmi_status_t)ECONNRESET);
|
||
|
return;
|
||
|
}
|
||
|
if (-1 == rval && !CMI_IO_WOULDBLOCK(errno))
|
||
|
{
|
||
|
cmj_err(lnk, CMI_REASON_STATUS, (cmi_status_t)errno);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
/* now we either have a positive rval or a no data error */
|
||
|
if (0 < rval)
|
||
|
{
|
||
|
if (NUM_IOVECS_BOTH == msg.msg_iovlen)
|
||
|
{
|
||
|
if ((CMI_TCP_PREFIX_LEN - lnk->ios.len_len) <= rval)
|
||
|
{
|
||
|
/* we now have the whole length */
|
||
|
rval -= (CMI_TCP_PREFIX_LEN - lnk->ios.len_len);
|
||
|
lnk->ios.len_len = CMI_TCP_PREFIX_LEN;
|
||
|
lnk->ios.u.len = ntohs(lnk->ios.u.len);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/* we just read part of the length */
|
||
|
assert(CMI_TCP_PREFIX_LEN > rval);
|
||
|
lnk->ios.len_len += (int)rval;
|
||
|
status = cmj_clb_set_async(lnk);
|
||
|
if (CMI_ERROR(status))
|
||
|
cmj_err(lnk, CMI_REASON_STATUS, status);
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
if (rval == (lnk->ios.u.len - lnk->ios.xfer_count))
|
||
|
{
|
||
|
lnk->ios.xfer_count += rval;
|
||
|
cmj_fini(lnk);
|
||
|
return;
|
||
|
}
|
||
|
lnk->ios.xfer_count += rval;
|
||
|
}
|
||
|
status = cmj_clb_set_async(lnk);
|
||
|
if (CMI_ERROR(status))
|
||
|
cmj_err(lnk, CMI_REASON_STATUS, status);
|
||
|
}
|