574 lines
21 KiB
C
574 lines
21 KiB
C
/****************************************************************
|
|
* *
|
|
* Copyright 2001, 2012 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. *
|
|
* *
|
|
****************************************************************/
|
|
|
|
/* iosocket_use.c */
|
|
#include "mdef.h"
|
|
|
|
#include "gtm_socket.h"
|
|
#include "gtm_unistd.h"
|
|
#include "gtm_iconv.h"
|
|
#include "gtm_stdio.h"
|
|
#include "gtm_string.h"
|
|
|
|
#include <errno.h>
|
|
#include "gtm_inet.h"
|
|
#include <netinet/tcp.h>
|
|
#include "copy.h"
|
|
#include "io.h"
|
|
#include "io_params.h"
|
|
#include "iotimer.h"
|
|
#include "iotcpdef.h"
|
|
#include "iotcproutine.h"
|
|
#include "gt_timer.h"
|
|
#include "iosocketdef.h"
|
|
#include "nametabtyp.h"
|
|
#include "namelook.h"
|
|
#include "stringpool.h"
|
|
#include "gtm_conv.h"
|
|
|
|
GBLREF io_pair io_curr_device;
|
|
GBLREF io_pair io_std_device;
|
|
GBLREF io_desc *active_device;
|
|
GBLREF tcp_library_struct tcp_routines;
|
|
GBLREF d_socket_struct *socket_pool;
|
|
GBLREF boolean_t gtm_utf8_mode;
|
|
GBLREF spdesc stringpool;
|
|
GBLREF UConverter *chset_desc[];
|
|
GBLREF int4 gtm_max_sockets;
|
|
GBLREF d_socket_struct *newdsocket;
|
|
GBLREF boolean_t dollar_zininterrupt;
|
|
|
|
LITREF nametabent filter_names[];
|
|
LITREF unsigned char filter_index[27];
|
|
LITREF unsigned char io_params_size[];
|
|
|
|
error_def(ERR_ABNCOMPTINC);
|
|
error_def(ERR_ACOMPTBINC);
|
|
error_def(ERR_ADDRTOOLONG);
|
|
error_def(ERR_ANCOMPTINC);
|
|
error_def(ERR_CURRSOCKOFR);
|
|
error_def(ERR_DELIMSIZNA);
|
|
error_def(ERR_DELIMWIDTH);
|
|
error_def(ERR_DEVPARMNEG);
|
|
error_def(ERR_ILLESOCKBFSIZE);
|
|
error_def(ERR_MRTMAXEXCEEDED);
|
|
error_def(ERR_SETSOCKOPTERR);
|
|
error_def(ERR_SOCKBFNOTEMPTY);
|
|
error_def(ERR_SOCKNOTFND);
|
|
error_def(ERR_SOCKMAX);
|
|
error_def(ERR_TEXT);
|
|
error_def(ERR_TTINVFILTER);
|
|
error_def(ERR_ZFF2MANY);
|
|
error_def(ERR_ZINTRECURSEIO);
|
|
|
|
void iosocket_use(io_desc *iod, mval *pp)
|
|
{
|
|
unsigned char ch, len;
|
|
int handled_len, handlea_len, handles_len;
|
|
int4 length, width, new_len;
|
|
d_socket_struct *dsocketptr;
|
|
socket_struct *socketptr, newsocket;
|
|
char handlea[MAX_HANDLE_LEN], handles[MAX_HANDLE_LEN], handled[MAX_HANDLE_LEN];
|
|
char addr[SA_MAXLITLEN], *errptr, sockaddr[SA_MAXLITLEN],
|
|
temp_addr[SA_MAXLITLEN], ioerror;
|
|
unsigned char delimiter_buffer[MAX_N_DELIMITER * (MAX_DELIM_LEN + 1)];
|
|
unsigned char zff_buffer[MAX_ZFF_LEN];
|
|
boolean_t attach_specified = FALSE,
|
|
detach_specified = FALSE,
|
|
connect_specified = FALSE,
|
|
ioerror_specified = FALSE,
|
|
listen_specified = FALSE,
|
|
socket_specified = FALSE,
|
|
delay_specified = FALSE,
|
|
nodelay_specified = FALSE,
|
|
bfsize_specified = FALSE,
|
|
ibfsize_specified = FALSE,
|
|
moreread_specified = FALSE,
|
|
create_new_socket;
|
|
int4 index, n_specified, zff_len, delimiter_len, moreread_timeout;
|
|
int fil_type, nodelay, p_offset = 0;
|
|
uint4 bfsize = DEFAULT_SOCKET_BUFFER_SIZE, ibfsize;
|
|
char *tab;
|
|
int save_errno;
|
|
size_t d_socket_struct_len;
|
|
mstr lcl_zff;
|
|
|
|
assert(iod->state == dev_open);
|
|
assert(iod->type == gtmsocket);
|
|
dsocketptr = (d_socket_struct *)(iod->dev_sp);
|
|
/* ---------------------------------- parse the command line ------------------------------------ */
|
|
n_specified = 0;
|
|
zff_len = -1; /* indicates neither ZFF nor ZNOFF specified */
|
|
delimiter_len = -1; /* indicates neither DELIM nor NODELIM specified */
|
|
|
|
/* A read or wait was interrupted for this device. Allow only parmless use in $zinterrupt code for
|
|
and interrupted device.
|
|
*/
|
|
if (iop_eol != *(pp->str.addr + p_offset))
|
|
{ /* Parameters were specified */
|
|
if (dsocketptr->mupintr)
|
|
{ /* And if we are in $zinterrupt code this is not allowed */
|
|
if (dollar_zininterrupt)
|
|
rts_error(VARLSTCNT(1) ERR_ZINTRECURSEIO);
|
|
/* We are not in $zinterrupt code and this device was not resumed properly
|
|
so clear its restartability.
|
|
*/
|
|
io_find_mvstent(iod, TRUE);
|
|
dsocketptr->mupintr = FALSE;
|
|
}
|
|
} else if (dsocketptr->mupintr && !dollar_zininterrupt)
|
|
{ /* The interrupted read was not properly resumed so clear it now */
|
|
dsocketptr->mupintr = FALSE;
|
|
dsocketptr->sock_save_state.who_saved = sockwhich_invalid;
|
|
io_find_mvstent(iod, TRUE);
|
|
}
|
|
|
|
while (iop_eol != (ch = *(pp->str.addr + p_offset++)))
|
|
{
|
|
assert((params)ch < (params)n_iops);
|
|
switch (ch)
|
|
{
|
|
case iop_exception:
|
|
iod->error_handler.len = *(pp->str.addr + p_offset);
|
|
iod->error_handler.addr = (char *)(pp->str.addr + p_offset + 1);
|
|
s2pool(&iod->error_handler);
|
|
break;
|
|
case iop_filter:
|
|
len = *(pp->str.addr + p_offset);
|
|
tab = pp->str.addr + p_offset + 1;
|
|
if ((fil_type = namelook(filter_index, filter_names, tab, len)) < 0)
|
|
{
|
|
rts_error(VARLSTCNT(1) ERR_TTINVFILTER);
|
|
return;
|
|
}
|
|
switch (fil_type)
|
|
{
|
|
case 0:
|
|
iod->write_filter |= CHAR_FILTER;
|
|
break;
|
|
case 1:
|
|
iod->write_filter |= ESC1;
|
|
break;
|
|
case 2:
|
|
iod->write_filter &= ~CHAR_FILTER;
|
|
break;
|
|
case 3:
|
|
iod->write_filter &= ~ESC1;
|
|
break;
|
|
}
|
|
break;
|
|
case iop_nofilter:
|
|
iod->write_filter = 0;
|
|
break;
|
|
case iop_attach:
|
|
n_specified++;
|
|
attach_specified = TRUE;
|
|
handlea_len = (int)(*(pp->str.addr + p_offset));
|
|
memcpy(handlea, (char *)(pp->str.addr + p_offset + 1), handlea_len);
|
|
break;
|
|
case iop_detach:
|
|
n_specified++;
|
|
detach_specified = TRUE;
|
|
handled_len = (int)(*(pp->str.addr + p_offset));
|
|
memcpy(handled, (char *)(pp->str.addr + p_offset + 1), handled_len);
|
|
break;
|
|
case iop_connect:
|
|
n_specified++;
|
|
connect_specified = TRUE;
|
|
len = *(pp->str.addr + p_offset);
|
|
if (len < SA_MAXLITLEN)
|
|
{
|
|
memcpy(sockaddr, (char *)(pp->str.addr + p_offset + 1), len);
|
|
sockaddr[len] = '\0';
|
|
} else
|
|
rts_error(VARLSTCNT(6) ERR_ADDRTOOLONG,
|
|
4, len, pp->str.addr + p_offset + 1, len, SA_MAXLITLEN);
|
|
break;
|
|
case iop_delimiter:
|
|
n_specified++;
|
|
delimiter_len = (int4)(unsigned char)*(pp->str.addr + p_offset);
|
|
if (((MAX_DELIM_LEN + 1) * MAX_N_DELIMITER) >= delimiter_len)
|
|
memcpy(delimiter_buffer, (pp->str.addr + p_offset + 1), delimiter_len);
|
|
else
|
|
rts_error(VARLSTCNT(1) ERR_DELIMSIZNA);
|
|
break;
|
|
case iop_nodelimiter:
|
|
delimiter_len = 0;
|
|
break;
|
|
case iop_zdelay:
|
|
delay_specified = TRUE;
|
|
break;
|
|
case iop_znodelay:
|
|
nodelay_specified = TRUE;
|
|
break;
|
|
case iop_zbfsize:
|
|
bfsize_specified = TRUE;
|
|
GET_ULONG(bfsize, pp->str.addr + p_offset);
|
|
if ((0 == bfsize) || (MAX_SOCKET_BUFFER_SIZE < bfsize))
|
|
rts_error(VARLSTCNT(3) ERR_ILLESOCKBFSIZE, 1, bfsize);
|
|
break;
|
|
case iop_zibfsize:
|
|
ibfsize_specified = TRUE;
|
|
GET_ULONG(ibfsize, pp->str.addr + p_offset);
|
|
if ((0 == ibfsize) || (MAX_INTERNAL_SOCBUF_SIZE < ibfsize))
|
|
rts_error(VARLSTCNT(3) ERR_ILLESOCKBFSIZE, 1, ibfsize);
|
|
break;
|
|
case iop_ioerror:
|
|
n_specified++;
|
|
ioerror_specified = TRUE;
|
|
ioerror = *(char *)(pp->str.addr + p_offset + 1);
|
|
break;
|
|
case iop_zlisten:
|
|
n_specified++;
|
|
listen_specified = TRUE;
|
|
len = *(pp->str.addr + p_offset);
|
|
if (len < SA_MAXLITLEN)
|
|
{
|
|
memcpy(sockaddr, (char *)(pp->str.addr + p_offset + 1), len);
|
|
sockaddr[len] = '\0';
|
|
} else
|
|
rts_error(VARLSTCNT(6) ERR_ADDRTOOLONG,
|
|
4, len, pp->str.addr + p_offset + 1, len, SA_MAXLITLEN);
|
|
break;
|
|
case iop_socket:
|
|
n_specified++;
|
|
socket_specified = TRUE;
|
|
handles_len = (int)(*(pp->str.addr + p_offset));
|
|
memcpy(handles, (char *)(pp->str.addr + p_offset + 1), handles_len);
|
|
break;
|
|
case iop_ipchset:
|
|
#if defined(KEEP_zOS_EBCDIC) || defined(VMS)
|
|
if ((iconv_t)0 != iod->input_conv_cd)
|
|
ICONV_CLOSE_CD(iod->input_conv_cd);
|
|
SET_CODE_SET(iod->in_code_set, (char *)(pp->str.addr + p_offset + 1));
|
|
if (DEFAULT_CODE_SET != iod->in_code_set)
|
|
ICONV_OPEN_CD(iod->input_conv_cd, INSIDE_CH_SET, (char *)(pp->str.addr + p_offset + 1));
|
|
#endif
|
|
break;
|
|
case iop_opchset:
|
|
#if defined(KEEP_zOS_EBCDIC) || defined(VMS)
|
|
if ((iconv_t)0 != iod->output_conv_cd)
|
|
ICONV_CLOSE_CD(iod->output_conv_cd);
|
|
SET_CODE_SET(iod->out_code_set, (char *)(pp->str.addr + p_offset + 1));
|
|
if (DEFAULT_CODE_SET != iod->out_code_set)
|
|
ICONV_OPEN_CD(iod->output_conv_cd, (char *)(pp->str.addr + p_offset + 1), INSIDE_CH_SET);
|
|
#endif
|
|
break;
|
|
case iop_zff:
|
|
if (MAX_ZFF_LEN >= (zff_len = (int4)(unsigned char)*(pp->str.addr + p_offset)))
|
|
memcpy(zff_buffer, (char *)(pp->str.addr + p_offset + 1), zff_len);
|
|
else
|
|
rts_error(VARLSTCNT(4) ERR_ZFF2MANY, 2, zff_len, MAX_ZFF_LEN);
|
|
break;
|
|
case iop_znoff:
|
|
zff_len = 0;
|
|
break;
|
|
case iop_length:
|
|
GET_LONG(length, pp->str.addr + p_offset);
|
|
if (length < 0)
|
|
rts_error(VARLSTCNT(1) ERR_DEVPARMNEG);
|
|
iod->length = length;
|
|
break;
|
|
case iop_width:
|
|
/* SOCKET WIDTH is handled the same way as TERMINAL WIDTH */
|
|
GET_LONG(width, pp->str.addr + p_offset);
|
|
if (width < 0)
|
|
rts_error(VARLSTCNT(1) ERR_DEVPARMNEG);
|
|
if (0 == width)
|
|
{
|
|
iod->width = TCPDEF_WIDTH;
|
|
iod->wrap = FALSE;
|
|
} else
|
|
{
|
|
iod->width = width;
|
|
iod->wrap = TRUE;
|
|
}
|
|
break;
|
|
case iop_wrap:
|
|
iod->wrap = TRUE;
|
|
break;
|
|
case iop_nowrap:
|
|
iod->wrap = FALSE;
|
|
break;
|
|
case iop_morereadtime:
|
|
/* Time in milliseconds socket read will wait for more data before returning */
|
|
GET_LONG(moreread_timeout, pp->str.addr + p_offset);
|
|
if (-1 == moreread_timeout)
|
|
moreread_timeout = DEFAULT_MOREREAD_TIMEOUT;
|
|
else if (-1 > moreread_timeout)
|
|
rts_error(VARLSTCNT(1) ERR_DEVPARMNEG);
|
|
else if (MAX_MOREREAD_TIMEOUT < moreread_timeout)
|
|
rts_error(VARLSTCNT(3) ERR_MRTMAXEXCEEDED, 1, MAX_MOREREAD_TIMEOUT);
|
|
moreread_specified = TRUE;
|
|
break;
|
|
default:
|
|
/* ignore deviceparm */
|
|
break;
|
|
}
|
|
p_offset += ((io_params_size[ch] == IOP_VAR_SIZE) ?
|
|
(unsigned char)*(pp->str.addr + p_offset) + 1 : io_params_size[ch]);
|
|
}
|
|
/* ------ return immediately if no flag, worth a check because it is mostly true ------------ */
|
|
if (1 == p_offset)
|
|
return;
|
|
/* ------------------------------ compatibility verification -------------------------------- */
|
|
if ((socket_specified) && ((n_specified > 2) || ((2 == n_specified) && (0 >= delimiter_len))))
|
|
{
|
|
rts_error(VARLSTCNT(8) ERR_ACOMPTBINC, 6, LEN_AND_LIT("SOCKET"), LEN_AND_LIT("DELIMITER"), LEN_AND_LIT("USE"));
|
|
return;
|
|
}
|
|
if (connect_specified && listen_specified)
|
|
{
|
|
rts_error(VARLSTCNT(8) ERR_ABNCOMPTINC, 6, LEN_AND_LIT("CONNECT"), LEN_AND_LIT("ZLISTEN"), LEN_AND_LIT("USE"));
|
|
return;
|
|
}
|
|
if (delay_specified && nodelay_specified)
|
|
{
|
|
rts_error(VARLSTCNT(8) ERR_ABNCOMPTINC, 6, LEN_AND_LIT("DELAY"), LEN_AND_LIT("NODELAY"), LEN_AND_LIT("OPEN"));
|
|
return;
|
|
}
|
|
/* ------------------ make a local copy of device structure to play with -------------------- */
|
|
d_socket_struct_len = SIZEOF(d_socket_struct) + (SIZEOF(socket_struct) * (gtm_max_sockets - 1));
|
|
memcpy(newdsocket, dsocketptr, d_socket_struct_len);
|
|
/* --------------- handle the two special cases attach/detach first ------------------------- */
|
|
if (detach_specified)
|
|
{
|
|
if (1 < n_specified)
|
|
{
|
|
rts_error(VARLSTCNT(6) ERR_ANCOMPTINC, 4, LEN_AND_LIT("DETACH"), LEN_AND_LIT("USE"));
|
|
return;
|
|
}
|
|
if (NULL == socket_pool)
|
|
iosocket_poolinit();
|
|
iosocket_switch(handled, handled_len, newdsocket, socket_pool);
|
|
memcpy(dsocketptr, newdsocket, d_socket_struct_len);
|
|
if (0 > dsocketptr->current_socket)
|
|
{
|
|
io_curr_device.in = io_std_device.in;
|
|
io_curr_device.out = io_std_device.out;
|
|
}
|
|
return; /* detach can only be specified by itself */
|
|
}
|
|
if (attach_specified)
|
|
{ /* NOTE: A socket could be moved from one device to another using DETACH/ATTACH. A socket does not carry I[O]CHSET with
|
|
* it while being moved. Such a socket will use the I[O]CHSET of the device it is ATTACHed to. If there is input still
|
|
* buffered, this may cause unintentional consequences in the application if I[O]CHSET changes. GT.M does not detect
|
|
* (or report) a change in I[O]CHSET due to DETACH/ATTACH.
|
|
*/
|
|
if (1 < n_specified)
|
|
{
|
|
rts_error(VARLSTCNT(6) ERR_ANCOMPTINC, 4, LEN_AND_LIT("ATTACH"), LEN_AND_LIT("USE"));
|
|
return;
|
|
}
|
|
if (NULL == socket_pool)
|
|
{
|
|
rts_error(VARLSTCNT(4) ERR_SOCKNOTFND, 2, handlea_len, handlea);
|
|
return;
|
|
}
|
|
iosocket_switch(handlea, handlea_len, socket_pool, newdsocket);
|
|
memcpy(dsocketptr, newdsocket, d_socket_struct_len);
|
|
return; /* attach can only be specified by itself */
|
|
}
|
|
/* ------------ create/identify the socket to work on and make a local copy ----------------- */
|
|
if (create_new_socket = (listen_specified || connect_specified)) /* real "=" */
|
|
{
|
|
/* allocate the structure for a new socket */
|
|
if (NULL == (socketptr = iosocket_create(sockaddr, bfsize, -1)))
|
|
return;
|
|
/* give the new socket a handle */
|
|
iosocket_handle(handles, &handles_len, TRUE, dsocketptr);
|
|
socketptr->handle_len = handles_len;
|
|
memcpy(socketptr->handle, handles, handles_len);
|
|
socketptr->dev = newdsocket; /* use newdsocket temporarily for the sake of bind/connect */
|
|
} else
|
|
{
|
|
if (socket_specified)
|
|
{
|
|
/* use the socket flag to identify which socket to apply changes */
|
|
if (0 > (index = iosocket_handle(handles, &handles_len, FALSE, newdsocket)))
|
|
{
|
|
rts_error(VARLSTCNT(4) ERR_SOCKNOTFND, 2, handles_len, handles);
|
|
return;
|
|
}
|
|
newdsocket->current_socket = index;
|
|
socketptr = newdsocket->socket[index];
|
|
} else
|
|
{
|
|
socketptr = newdsocket->socket[newdsocket->current_socket];
|
|
if (newdsocket->n_socket <= newdsocket->current_socket)
|
|
{
|
|
assert(FALSE);
|
|
rts_error(VARLSTCNT(4) ERR_CURRSOCKOFR, 2, newdsocket->current_socket, newdsocket->n_socket);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
newsocket = *socketptr;
|
|
/* ---------------------- apply changes to the local copy of the socket --------------------- */
|
|
if (0 <= delimiter_len)
|
|
{
|
|
iosocket_delimiter(delimiter_buffer, delimiter_len, &newsocket, (0 == delimiter_len));
|
|
/* The delimiter has changed. The iosocket_readfl/write routine won't notice so we have to do
|
|
the UTF16xx conversion since we changed it.
|
|
*/
|
|
DBGSOCK2((stdout, "socuse: Delimiter(s) replaced - num delims: %d delimiter_len: %d ichset: %d ochset: %d\n",
|
|
newsocket.n_delimiter, delimiter_len, iod->ichset, iod->ochset));
|
|
if (0 < delimiter_len)
|
|
{
|
|
if (!newsocket.first_read && (CHSET_UTF16BE == iod->ichset || CHSET_UTF16LE == iod->ichset))
|
|
{ /* We have been reading with this socket so convert this new delimiter set */
|
|
DBGSOCK2((stdout, "socuse: Converting new delimiters for input\n"));
|
|
iosocket_delim_conv(&newsocket, iod->ichset);
|
|
}
|
|
if (!newsocket.first_write && (CHSET_UTF16BE == iod->ochset || CHSET_UTF16LE == iod->ochset))
|
|
{ /* We have been writing with this socket so convert the new default output delimiter */
|
|
DBGSOCK2((stdout, "socuse: Converting new delimiters for output\n"));
|
|
if (newsocket.first_read || (CHSET_UTF16BE != iod->ichset && CHSET_UTF16LE != iod->ichset))
|
|
{ /* Need to do conversion as iosocket_delim_conv above didn't do it for us */
|
|
DBGSOCK2((stdout, "socuse: running convert for write since input didn't do it\n"));
|
|
new_len = gtm_conv(chset_desc[CHSET_UTF8], chset_desc[iod->ochset],
|
|
&newsocket.delimiter[0], NULL, NULL);
|
|
if (MAX_DELIM_LEN < new_len)
|
|
{
|
|
rts_error(VARLSTCNT(1) ERR_DELIMSIZNA);
|
|
return;
|
|
}
|
|
} else
|
|
{
|
|
DBGSOCK2((stdout, "socuse: using previous length from read conversion\n"));
|
|
new_len = newsocket.idelimiter[0].len;
|
|
}
|
|
newsocket.odelimiter0.len = new_len;
|
|
UNICODE_ONLY(newsocket.odelimiter0.char_len = newsocket.delimiter[0].char_len);
|
|
newsocket.odelimiter0.addr = malloc(new_len);
|
|
memcpy(newsocket.odelimiter0.addr,
|
|
(newsocket.first_read ? (char *)stringpool.free : newsocket.idelimiter[0].addr),
|
|
new_len);
|
|
}
|
|
}
|
|
}
|
|
if (iod->wrap && 0 != newsocket.n_delimiter && iod->width < newsocket.delimiter[0].len)
|
|
rts_error(VARLSTCNT(4) ERR_DELIMWIDTH, 2, iod->width, newsocket.delimiter[0].len);
|
|
if (0 <= zff_len && /* ZFF or ZNOFF specified */
|
|
0 < (newsocket.zff.len = zff_len)) /* assign the new ZFF len, might be 0 from ZNOFF, or ZFF="" */
|
|
{ /* ZFF="non-zero-len-string" specified */
|
|
if (CHSET_UTF16BE == iod->ochset || CHSET_UTF16LE == iod->ochset) /* need conversion of ZFF */
|
|
{
|
|
DBGSOCK2((stdout, "socuse: Converting zff\n"));
|
|
lcl_zff.addr = (char *)zff_buffer;
|
|
lcl_zff.len = zff_len;
|
|
new_len = gtm_conv(chset_desc[CHSET_UTF8], chset_desc[iod->ochset], &lcl_zff, NULL, NULL);
|
|
if (MAX_ZFF_LEN < new_len)
|
|
rts_error(VARLSTCNT(4) ERR_ZFF2MANY, 2, new_len, MAX_ZFF_LEN);
|
|
if (NULL == newsocket.zff.addr) /* we rely on newsocket.zff.addr being set to 0 in iosocket_create() */
|
|
newsocket.zff.addr = (char *)malloc(MAX_ZFF_LEN);
|
|
newsocket.zff.len = new_len;
|
|
UNICODE_ONLY(newsocket.zff.char_len = 0); /* don't care */
|
|
memcpy(newsocket.zff.addr, stringpool.free, new_len);
|
|
|
|
} else
|
|
{ /* Store parm without conversion */
|
|
if (gtm_utf8_mode) /* Check if ZFF has any invalid UTF-8 character */
|
|
{ /* Note: the ZFF string originates from the source program, so is in UTF-8 mode or M mode
|
|
regardless of OCHSET of this device. ZFF is output on WRITE # command, and MUST contain
|
|
valid UTF-8 sequence. This validation is handled by gtm_conv in the path above.
|
|
*/
|
|
utf8_len_strict(zff_buffer, zff_len);
|
|
}
|
|
if (NULL == newsocket.zff.addr) /* we rely on newsocket.zff.addr being set to 0 in iosocket_create() */
|
|
newsocket.zff.addr = (char *)malloc(MAX_ZFF_LEN);
|
|
memcpy(newsocket.zff.addr, zff_buffer, zff_len);
|
|
}
|
|
}
|
|
if (ioerror_specified)
|
|
newsocket.ioerror = ('T' == ioerror || 't' == ioerror);
|
|
if (nodelay_specified || delay_specified)
|
|
newsocket.nodelay = nodelay_specified; /* defaults to DELAY */
|
|
if (ibfsize_specified)
|
|
newsocket.bufsiz = ibfsize;
|
|
if (moreread_specified)
|
|
{
|
|
newsocket.moreread_timeout = moreread_timeout;
|
|
newsocket.def_moreread_timeout = TRUE; /* need to know this was user-defined in iosocket_readfl.c */
|
|
}
|
|
if (!create_new_socket)
|
|
{
|
|
/* these changes apply to only pre-existing sockets */
|
|
if (bfsize_specified)
|
|
newsocket.buffer_size = bfsize;
|
|
#ifdef TCP_NODELAY
|
|
nodelay = newsocket.nodelay ? 1 : 0;
|
|
if ((socketptr->nodelay != newsocket.nodelay) &&
|
|
(-1 == tcp_routines.aa_setsockopt(newsocket.sd, IPPROTO_TCP,
|
|
TCP_NODELAY, &nodelay, SIZEOF(nodelay))))
|
|
{
|
|
save_errno = errno;
|
|
errptr = (char *)STRERROR(save_errno);
|
|
rts_error(VARLSTCNT(7) ERR_SETSOCKOPTERR, 5, LEN_AND_LIT("TCP_NODELAY"), save_errno, LEN_AND_STR(errptr));
|
|
return;
|
|
}
|
|
#endif
|
|
if ((socketptr->bufsiz != newsocket.bufsiz) &&
|
|
(-1 == tcp_routines.aa_setsockopt(newsocket.sd, SOL_SOCKET,
|
|
SO_RCVBUF, &newsocket.bufsiz, SIZEOF(newsocket.bufsiz))))
|
|
{
|
|
save_errno = errno;
|
|
errptr = (char *)STRERROR(save_errno);
|
|
rts_error(VARLSTCNT(7) ERR_SETSOCKOPTERR, 5, LEN_AND_LIT("SO_RCVBUF"), save_errno, LEN_AND_STR(errptr));
|
|
return;
|
|
}
|
|
if (socketptr->buffer_size != newsocket.buffer_size)
|
|
{
|
|
if (socketptr->buffered_length > bfsize)
|
|
rts_error(VARLSTCNT(4) ERR_SOCKBFNOTEMPTY, 2, bfsize, socketptr->buffered_length);
|
|
newsocket.buffer = (char *)malloc(bfsize);
|
|
if (0 < socketptr->buffered_length)
|
|
{
|
|
memcpy(newsocket.buffer, socketptr->buffer + socketptr->buffered_offset,
|
|
socketptr->buffered_length);
|
|
newsocket.buffered_offset = 0;
|
|
}
|
|
}
|
|
}
|
|
/* -------------------------------------- action -------------------------------------------- */
|
|
if ((listen_specified && (!iosocket_bind(&newsocket, NO_M_TIMEOUT, ibfsize_specified))) ||
|
|
(connect_specified && (!iosocket_connect(&newsocket, 0, ibfsize_specified))))
|
|
{ /* error message should be printed from bind/connect */
|
|
if (socketptr->sd > 0)
|
|
(void)tcp_routines.aa_close(socketptr->sd);
|
|
iosocket_delimiter((unsigned char *)NULL, 0, &newsocket, TRUE);
|
|
if (NULL != socketptr->zff.addr)
|
|
free(socketptr->zff.addr);
|
|
if (NULL != socketptr->buffer)
|
|
free(socketptr->buffer);
|
|
free(socketptr);
|
|
return;
|
|
}
|
|
/* ------------------------------------ commit changes -------------------------------------- */
|
|
if (create_new_socket)
|
|
{
|
|
if (gtm_max_sockets <= newdsocket->n_socket)
|
|
{
|
|
rts_error(VARLSTCNT(3) ERR_SOCKMAX, 1, gtm_max_sockets);
|
|
return;
|
|
}
|
|
/* a new socket is created. so add to the list */
|
|
newsocket.dev = dsocketptr;
|
|
newdsocket->socket[newdsocket->n_socket++] = socketptr;
|
|
newdsocket->current_socket = newdsocket->n_socket - 1;
|
|
}
|
|
else if (socketptr->buffer_size != newsocket.buffer_size)
|
|
free(socketptr->buffer);
|
|
*socketptr = newsocket;
|
|
memcpy(dsocketptr, newdsocket, d_socket_struct_len);
|
|
return;
|
|
}
|