windows-nt/Source/XPSP1/NT/net/streams/winstrm/s_putmsg.c
2020-09-26 16:20:57 +08:00

165 lines
4.5 KiB
C

/*++
Copyright (c) 1991 Microsoft Corporation
Module Name:
s_putmsg.c
Abstract:
This module implements the STREAMS APIs, ioctl(I_FDINSERT) and
putmsg().
Author:
Eric Chin (ericc) July 26, 1991
Revision History:
Sam Patton (sampa) August 13, 1991
changed errno to {get|set}lasterror
--*/
#include "common.h"
int
putmsg(
IN HANDLE fd,
IN struct strbuf *ctrlptr OPTIONAL,
IN struct strbuf *dataptr OPTIONAL,
IN int flags
)
/*++
Routine Description:
This function is called to send a STREAMS message downstream.
This function is synchronous, in the NT sense: it blocks until the API
completes.
Arguments:
fd - NT file handle
ctrlptr - pointer to the control portion of the STREAMS message
dataptr - pointer to the data portion of the STREAMS message
flags - 0 or RS_HIPRI
Return Value:
0 if successful, -1 otherwise.
--*/
{
char *tmp;
int chunksz;
NTSTATUS status;
IO_STATUS_BLOCK iosb;
PSTRM_ARGS_OUT oparm;
PPUTMSG_ARGS_IN chunk;
int retval;
//
// marshall the arguments into one contiguous chunk. However, for
// commonality with ioctl(I_FDINSERT), we arrange the input arguments
// as below:
//
// typedef struct _PUTMSG_ARGS_IN_ {
// int a_iocode; // 0
// long a_flags; // 0 | RS_HIPRI
// struct strbuf a_ctlbuf; // (required)
// struct strbuf a_databuf; // (required)
// HANDLE a_insert.i_fildes; // -1
// int a_offset; // 0
// char a_stuff[1]; // s_ctlbuf.buf (optional)
// // s_databuf.buf (optional)
// } PUTMSG_ARGS_IN, *PPUTMSG_ARGS_IN;
//
//
chunksz = sizeof(PUTMSG_ARGS_IN) - 1 +
((ctrlptr && (ctrlptr->len > 0)) ? ctrlptr->len : 0) +
((dataptr && (dataptr->len > 0)) ? dataptr->len : 0);
if (!(chunk = (PPUTMSG_ARGS_IN) LocalAlloc(LMEM_FIXED, chunksz))) {
SetLastError(ENOSPC);
return(-1);
}
chunk->a_iocode = 0;
chunk->a_flags = (long) flags;
tmp = (char *) chunk->a_stuff;
if (ctrlptr && ctrlptr->buf && (ctrlptr->len >= 0)) {
chunk->a_ctlbuf = *ctrlptr; // structure copy
memcpy(tmp, ctrlptr->buf, ctrlptr->len);
tmp += ctrlptr->len;
}
else {
chunk->a_ctlbuf.len = -1;
}
if (dataptr && dataptr->buf && (dataptr->len >= 0)) {
chunk->a_databuf = *dataptr; // structure copy
memcpy(tmp, dataptr->buf, dataptr->len);
tmp += dataptr->len;
}
else {
chunk->a_databuf.len = -1;
}
chunk->a_insert.i_fildes = INVALID_HANDLE_VALUE;
chunk->a_offset = 0;
ASSERT(chunksz >= sizeof(STRM_ARGS_OUT));
status = NtDeviceIoControlFile(
fd, // Handle
NULL, // Event
NULL, // ApcRoutine
NULL, // ApcContext
&iosb, // IoStatusBlock
IOCTL_STREAMS_PUTMSG, // IoControlCode
(PVOID) chunk, // InputBuffer
chunksz, // InputBufferSize
(PVOID) chunk, // OutputBuffer
chunksz); // OutputBufferSize
if (status == STATUS_PENDING) {
status = NtWaitForSingleObject(
fd, // Handle
TRUE, // Alertable
NULL); // Timeout
}
if (!NT_SUCCESS(status)) {
LocalFree(chunk);
SetLastError(MapNtToPosixStatus(status));
return(-1);
}
//
// the return parameters from the Stream Head Driver are laid out as:
//
// typedef struct _STRM_ARGS_OUT_ { // generic return parameters
// int a_retval; // return value
// int a_errno; // errno if retval == -1
//
// } STRM_ARGS_OUT, *PSTRM_ARGS_OUT;
//
oparm = (PSTRM_ARGS_OUT) chunk;
if (oparm->a_retval == -1) {
SetLastError(oparm->a_errno);
}
retval = oparm->a_retval;
LocalFree(chunk);
return(retval);
} // putmsg