fis-gtm/sr_unix_gnp/cmj_write.c

227 lines
6.3 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"
GBLREF struct NTD *ntd_root;
#define NUM_IOVECS 2
#define IOVEC_LEN 0
#define IOVEC_MSG 1
cmi_status_t cmj_write_start(struct CLB *lnk)
{
cmi_status_t status = SS_NORMAL;
struct msghdr msg;
struct iovec vec[NUM_IOVECS];
int save_errno;
ssize_t rval;
error_def(CMI_DCNINPROG);
error_def(CMI_LNKNOTIDLE);
error_def(CMI_OVERRUN);
if (lnk->mun == -1)
return ENOTCONN;
if (lnk->sta != CM_CLB_IDLE)
return (lnk->sta == CM_CLB_DISCONNECT) ? CMI_DCNINPROG : CMI_LNKNOTIDLE;
lnk->sta = CM_CLB_WRITE;
CMI_CLB_IOSTATUS(lnk) = SS_NORMAL;
memset(&msg, 0, SIZEOF(msg));
msg.msg_iovlen = NUM_IOVECS; /* two vectors */
msg.msg_iov = vec;
vec[IOVEC_LEN].iov_len = CMI_TCP_PREFIX_LEN;
vec[IOVEC_LEN].iov_base = (caddr_t)lnk->ios.u.lenbuf;
lnk->ios.u.len = htons((unsigned short)lnk->cbl); /* length of message is sent in network byte order */
vec[IOVEC_MSG].iov_len = lnk->cbl;
vec[IOVEC_MSG].iov_base = (caddr_t)lnk->mbf;
/*
* Use sendmsg to cut down number of system calls
* and more importantly, since we probably have
* disabled the nagle algorithm, insure that the tcp socket
* is presented with an opportunity to write
* the entire packet.
*
* I didn't change the interrupt handler, since
* a partially successful write is an exception.
*
*/
while ((-1 == (rval = sendmsg(lnk->mun, &msg, 0))) && EINTR == errno)
;
if (-1 == rval)
{
save_errno = errno;
CMI_DPRINT(("cmj_write_start: sendmsg error code : %d\n", save_errno));
if (!CMI_IO_WOULDBLOCK(save_errno))
{
cmj_err(lnk, CMI_REASON_STATUS, save_errno);
cmj_postevent(lnk);
return save_errno;
}
}
if (rval >= CMI_TCP_PREFIX_LEN)
{
/* we wrote at least the entire length */
lnk->ios.len_len = CMI_TCP_PREFIX_LEN;
rval -= CMI_TCP_PREFIX_LEN; /* subtract out length overhead */
lnk->ios.xfer_count = rval;
if (rval == lnk->cbl)
{
cmj_fini(lnk); /* done */
return status;
}
/* After successfully sending message length, convert length back to host order since we use this to compute
* length remaining for partial sends */
lnk->ios.u.len = ntohs((unsigned short)lnk->ios.u.len);
} else
{
/* partial or no write of length */
if (rval > 0)
{
assert(CMI_TCP_PREFIX_LEN > rval);
lnk->ios.len_len = (int)rval;
}
}
CMI_DPRINT(("cmj_write_start: sendmsg partial send %ld bytes\n", rval));
status = cmj_clb_set_async(lnk); /* more to write */
return status;
}
cmi_status_t cmj_write_urg_start(struct CLB *lnk)
{
cmi_status_t status = SS_NORMAL;
ssize_t rval;
error_def(CMI_DCNINPROG);
error_def(CMI_LNKNOTIDLE);
error_def(CMI_OVERRUN);
if (lnk->mun == -1)
return ENOTCONN;
lnk->prev_sta = lnk->sta;
lnk->sta = CM_CLB_WRITE_URG;
while ((-1 == (rval = send(lnk->mun, (void *)&lnk->urgdata, 1, MSG_OOB))) && EINTR == errno)
;
if (-1 == rval && !CMI_IO_WOULDBLOCK(errno))
return errno;
if (1 == rval)
{
cmj_fini(lnk);
return status;
}
status = cmj_clb_set_async(lnk); /* could not send 1 byte urgent data, try again. NOTE: no length prefix for urgent data */
return status;
}
void cmj_write_interrupt(struct CLB *lnk, int signo)
{
int save_errno;
ssize_t rval;
cmi_status_t status = SS_NORMAL;
if (lnk->mun == -1)
return;
if (lnk->sta == CM_CLB_WRITE_URG)
{
while ((-1 == (rval = send(lnk->mun, (void *)&lnk->urgdata, 1, MSG_OOB))) && EINTR == errno)
;
if (-1 == rval)
{
save_errno = errno;
CMI_DPRINT(("cmj_write_interrupt : send URGENT error code : %d\n", save_errno));
if (!CMI_IO_WOULDBLOCK(save_errno))
{
cmj_err(lnk, CMI_REASON_STATUS, (cmi_status_t)save_errno);
return;
}
}
if (1 == rval)
{
cmj_fini(lnk);
return;
}
status = cmj_clb_set_async(lnk);
if (CMI_ERROR(status))
cmj_err(lnk, CMI_REASON_STATUS, status);
return;
}
if (lnk->ios.len_len < CMI_TCP_PREFIX_LEN)
{
while ((-1 == (rval = send(lnk->mun, (void *)(lnk->ios.u.lenbuf + lnk->ios.len_len),
CMI_TCP_PREFIX_LEN - lnk->ios.len_len, 0))) && EINTR == errno)
;
if (-1 == rval)
{
save_errno = errno;
CMI_DPRINT(("cmj_write_interrupt : send error code : %d\n", save_errno));
if (!CMI_IO_WOULDBLOCK(save_errno))
{
cmj_err(lnk, CMI_REASON_STATUS, (cmi_status_t)save_errno);
return;
}
}
if (rval > 0)
{
lnk->ios.len_len += (int)rval;
assert(CMI_TCP_PREFIX_LEN >= lnk->ios.len_len);
if (lnk->ios.len_len == CMI_TCP_PREFIX_LEN) /* prefix length successfully sent */
{
/* After successfully sending message length, convert length back to host order since we use
* this to compute length remaining for partial sends */
lnk->ios.u.len = ntohs((unsigned short)lnk->ios.u.len);
}
} else
{
CMI_DPRINT(("cmj_write_interrupt : send wrote 0 bytes\n"));
}
}
if (lnk->ios.len_len == CMI_TCP_PREFIX_LEN)
{
assert(lnk->ios.u.len > lnk->ios.xfer_count); /* we shouldn't be wasting system calls on doing 0 byte output */
while ((-1 == (rval = send(lnk->mun, (void *)(lnk->mbf + lnk->ios.xfer_count),
(int)(lnk->ios.u.len - lnk->ios.xfer_count), 0))) && EINTR == errno)
;
if (-1 == rval && !CMI_IO_WOULDBLOCK(errno))
{
cmj_err(lnk, CMI_REASON_STATUS, (cmi_status_t)errno);
return;
}
if (rval > 0)
lnk->ios.xfer_count += rval;
if (0 == (int)(lnk->ios.u.len - lnk->ios.xfer_count)) /* entire message successfully sent */
cmj_fini(lnk);
else
{
status = cmj_clb_set_async(lnk);
if (CMI_ERROR(status))
cmj_err(lnk, CMI_REASON_STATUS, status);
CMI_DPRINT(("cmj_write_interrupt: send partial (1) send %ld bytes\n", rval));
}
}
else
{
/* partial or no write of length */
if (rval > 0)
{
lnk->ios.len_len += (int)rval;
assert(CMI_TCP_PREFIX_LEN > lnk->ios.len_len);
}
status = cmj_clb_set_async(lnk);
if (CMI_ERROR(status))
cmj_err(lnk, CMI_REASON_STATUS, status);
CMI_DPRINT(("cmj_write_interrupt: send partial (2) send %ld bytes\n", rval));
}
}