windows-nt/Source/XPSP1/NT/net/streams/winstrm/s_getmsg.c

204 lines
5.6 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
Copyright (c) 1991 Microsoft Corporation
Module Name:
s_getmsg.c
Abstract:
This module implements the STREAMS api, getmsg().
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
getmsg(
IN HANDLE fd,
IN OUT struct strbuf *ctrlptr OPTIONAL,
IN OUT struct strbuf *dataptr OPTIONAL,
IN OUT int *flagsp
)
/*++
Routine Description:
This procedure is called to receive a STREAMS message.
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
flagsp - pointer to the flags argument, which may be RS_HIPRI
Return Value:
0, MORECTL and/or MOREDATA bits set if successful, -1 otherwise.
--*/
{
char *tmp;
int chunksz;
NTSTATUS status;
PSTRM_ARGS_OUT oparm;
IO_STATUS_BLOCK iosb;
PGETMSG_ARGS_INOUT chunk;
int retval;
//
// marshall the arguments into one contiguous chunk, laid out as:
//
// typedef struct _GETMSG_ARGS_INOUT_ {
// int a_retval; // ignored for input
// long a_flags; // 0 or RS_HIPRI
// struct strbuf a_ctlbuf; // (required)
// struct strbuf a_databuf; // (required)
// char a_stuff[1]; // a_ctlbuf.buf (optional)
// // a_databuf.buf (optional)
// } GETMSG_ARGS_INOUT, *PGETMSG_ARGS_INOUT;
//
//
chunksz = sizeof(GETMSG_ARGS_INOUT) - 1 +
((ctrlptr && (ctrlptr->maxlen > 0)) ? ctrlptr->maxlen : 0) +
((dataptr && (dataptr->maxlen > 0)) ? dataptr->maxlen : 0);
if (!(chunk = (PGETMSG_ARGS_INOUT) LocalAlloc(LMEM_FIXED, chunksz))) {
SetLastError(ENOSPC);
return(-1);
}
chunk->a_flags = (long) *flagsp;
memset(&(chunk->a_ctlbuf), 0, 2 * sizeof(struct strbuf));
if (ctrlptr) {
chunk->a_ctlbuf = *ctrlptr; // structure copy
}
if (dataptr) {
chunk->a_databuf = *dataptr; // structure copy
}
status = NtDeviceIoControlFile(
fd, // Handle
NULL, // Event
NULL, // ApcRoutine
NULL, // ApcContext
&iosb, // IoStatusBlock
IOCTL_STREAMS_GETMSG, // IoControlCode
(PVOID) chunk, // InputBuffer
chunksz, // InputBufferSize
(PVOID) chunk, // OutputBuffer
chunksz); // OutputBufferSize
if (status == STATUS_PENDING) {
status = NtWaitForSingleObject(
fd, // Handle
TRUE, // Alertable
NULL); // Timeout
}
if (status != STATUS_SUCCESS) {
LocalFree(chunk);
SetLastError(MapNtToPosixStatus(status));
return(-1);
}
//
// sampa
//
#if 0
if (status == STATUS_PENDING)
{
TimeOut.LowPart = 30L; // 30 second
TimeOut.HighPart = 0L;
TimeOut = RtlExtendedIntegerMultiply(TimeOut, 1000000L);
status =
NtWaitForSingleObject(
fd,
TRUE,
NULL);
if (status != STATUS_SUCCESS) {
SetLastError(MapNtToPosixStatus(status));
LocalFree((HANDLE) chunk);
return(-1);
}
}
#endif
//
// if there was an error, 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);
}
// otherwise, the return parameters from the Stream Head Driver are laid
// out as:
//
// typedef struct _GETMSG_ARGS_INOUT_ {
// int a_retval; // ignored for input
// long a_flags; // 0 or RS_HIPRI
// struct strbuf a_ctlbuf; // (required)
// struct strbuf a_databuf; // (required)
// char a_stuff[1]; // a_ctlbuf.buf (optional)
// // a_databuf.buf (optional)
// } GETMSG_ARGS_INOUT, *PGETMSG_ARGS_INOUT;
//
//
*flagsp = chunk->a_flags;
tmp = chunk->a_stuff;
if (ctrlptr) {
ctrlptr->len = chunk->a_ctlbuf.len;
if (ctrlptr->len > 0) {
assert(ctrlptr->len <= ctrlptr->maxlen);
memcpy(ctrlptr->buf, tmp, ctrlptr->len);
tmp += ctrlptr->len;
}
}
if (dataptr) {
dataptr->len = chunk->a_databuf.len;
if (dataptr->len > 0) {
assert(dataptr->len <= dataptr->maxlen);
memcpy(dataptr->buf, tmp, dataptr->len);
}
}
retval = chunk->a_retval;
LocalFree(chunk);
return(retval);
} // getmsg