📄 sendmsg.c
字号:
/* If this message is routable, find its target object */
if( handlingInfoPtr->routingFunction != NULL )
{
/* If it's implicitly routed, route it based on the attribute type */
if( isImplicitRouting( handlingInfoPtr->routingTarget ) )
{
if( attributeACL->routingFunction != NULL )
localObjectHandle = attributeACL->routingFunction( objectHandle,
attributeACL->routingTarget );
}
else
/* It's explicitly or directly routed, route it based on the
message type or fixed-target type */
localObjectHandle = handlingInfoPtr->routingFunction( objectHandle,
isExplicitRouting( handlingInfoPtr->routingTarget ) ? \
messageValue : handlingInfoPtr->routingTarget );
if( cryptStatusError( localObjectHandle ) )
{
MUTEX_UNLOCK( objectTable );
return( CRYPT_ARGERROR_OBJECT );
}
}
/* Inner precodition: It's a valid destination object */
PRE( isValidObject( localObjectHandle ) );
/* It's a valid object, get its info */
objectInfoPtr = &objectTable[ localObjectHandle ];
/* Now that the message has been routed to its intended target, make sure
that it's valid for the target object subtype */
if( !isValidSubtype( handlingInfoPtr->subTypeA, objectInfoPtr->subType ) && \
!isValidSubtype( handlingInfoPtr->subTypeB, objectInfoPtr->subType ) )
{
MUTEX_UNLOCK( objectTable );
return( CRYPT_ARGERROR_OBJECT );
}
/* Inner precondition: The message is valid for this object subtype */
PRE( isValidSubtype( handlingInfoPtr->subTypeA, objectInfoPtr->subType ) || \
isValidSubtype( handlingInfoPtr->subTypeB, objectInfoPtr->subType ) );
/* If this message is processed internally, handle it now. These
messages aren't affected by the object's state so they're always
processed */
if( handlingInfoPtr->internalHandlerFunction != NULL || \
( attributeACL != NULL && \
attributeACL->flags & ATTRIBUTE_FLAG_PROPERTY ) )
{
if( handlingInfoPtr->preDispatchFunction != NULL )
status = handlingInfoPtr->preDispatchFunction( localObjectHandle,
message, messageDataPtr, messageValue,
aclPtr );
if( cryptStatusOK( status ) )
{
/* Precondition: Either the message as a whole is internally
handled or it's a property attribute */
PRE( handlingInfoPtr->internalHandlerFunction == NULL || \
attributeACL == NULL );
/* If it's an object property attribute (which is handled by the
kernel), get or set its value */
if( handlingInfoPtr->internalHandlerFunction == NULL )
{
/* Precondition: Object properties are always numeric
attributes */
PRE( handlingInfoPtr->messageType == MESSAGE_GETATTRIBUTE || \
handlingInfoPtr->messageType == MESSAGE_SETATTRIBUTE );
if( handlingInfoPtr->messageType == MESSAGE_GETATTRIBUTE )
status = getPropertyAttribute( localObjectHandle,
messageValue, messageDataPtr );
else
status = setPropertyAttribute( localObjectHandle,
messageValue, messageDataPtr );
}
else
/* It's a kernel-handled message, process it */
status = handlingInfoPtr->internalHandlerFunction( \
localObjectHandle, messageValue,
messageDataPtr, isInternalMessage );
if( cryptStatusOK( status ) && \
handlingInfoPtr->postDispatchFunction != NULL )
status = handlingInfoPtr->postDispatchFunction( localObjectHandle,
message, messageDataPtr, messageValue, aclPtr );
}
if( status != OK_SPECIAL )
{
/* The message was processed normally, exit */
MUTEX_UNLOCK( objectTable );
return( status );
}
/* The object has entered an invalid state (for example it was
signalled while it was being initialised) and can't be used any
more, destroy it, convert the (local copy of the) message into a
destroy object message */
localMessage = MESSAGE_DESTROY;
status = CRYPT_OK;
}
#if 0 /* 18/2/04 No need for copy-on-write any more since we can just copy
across the instance data referenced in the object table */
/* If this is an aliased object (one that's been cloned and is subject
to copy-on-write), handle it specially */
if( isAliasedObject( localObjectHandle ) )
{
status = handleAliasedObject( localObjectHandle, localMessage,
messageDataPtr, messageValue );
if( cryptStatusError( status ) )
{
MUTEX_UNLOCK( objectTable );
return( status );
}
}
#else
/* We shouldn't have aliased objects since we don't use copy-on-write
any more */
assert( !isAliasedObject( localObjectHandle ) );
#endif /* 0 */
/* If the object isn't already processing a message and the message isn't
a special type such as MESSAGE_DESTROY, dispatch it immediately rather
than enqueueing it for later dispatch. This scoreboard mechanism
greatly reduces the load on the queue */
if( !isInUse( localObjectHandle ) && localMessage != MESSAGE_DESTROY )
{
CONST_INIT_STRUCT_5( MESSAGE_QUEUE_DATA messageQueueData, \
localObjectHandle, handlingInfoPtr, message, \
messageDataPtr, messageValue );
CONST_SET_STRUCT( messageQueueData.objectHandle = localObjectHandle; \
messageQueueData.handlingInfoPtr = handlingInfoPtr; \
messageQueueData.message = message; \
messageQueueData.messageDataPtr = messageDataPtr; \
messageQueueData.messageValue = messageValue );
/* If the object isn't in a valid state, we can't do anything with it.
There are no messages that can be sent to it at this point, get/
set property messages have already been handled earlier and the
destroy message isn't handled here */
if( isInvalidObjectState( localObjectHandle ) )
{
status = getObjectStatusValue( objectInfoPtr->flags );
MUTEX_UNLOCK( objectTable );
return( status );
}
/* In case a shutdown was signalled while we were performing other
processing, exit now before we try and do anything with the
object. It's safe to perform the check at this point since no
message sent during shutdown will get here */
if( krnlData->shutdownLevel >= SHUTDOWN_LEVEL_MESSAGES )
{
MUTEX_UNLOCK( objectTable );
return( CRYPT_ERROR_PERMISSION );
}
/* Inner precondition: The object is in a valid state */
PRE( !isInvalidObjectState( localObjectHandle ) );
/* Dispatch the message to the object */
status = dispatchMessage( localObjectHandle, &messageQueueData,
objectInfoPtr, aclPtr );
MUTEX_UNLOCK( objectTable );
/* Postcondition: The return status is valid */
POST( ( status >= CRYPT_ENVELOPE_RESOURCE && status <= CRYPT_OK ) || \
cryptArgError( status ) || status == OK_SPECIAL );
return( status );
}
/* Inner precondition: The object is in use or it's a destroy object
message, we have to enqueue it */
PRE( isInUse( localObjectHandle ) || localMessage == MESSAGE_DESTROY );
/* If we're stuck in a loop processing recursive messages, bail out.
This would happen automatically anyway once we fill the message queue,
but this early-out mechanism prevents a single object from filling the
queue to the detriment of other objects */
if( objectInfoPtr->lockCount > MESSAGE_QUEUE_SIZE / 2 )
{
MUTEX_UNLOCK( objectTable );
assert( NOTREACHED );
return( CRYPT_ERROR_TIMEOUT );
}
/* If the object is in use by another thread, wait for it to become
available */
if( isInUse( objectHandle ) && !isObjectOwner( objectHandle ) )
status = waitForObject( objectHandle, &objectInfoPtr );
if( cryptStatusError( status ) )
{
MUTEX_UNLOCK( objectTable );
return( status );
}
/* Enqueue the message */
if( ( message & MESSAGE_MASK ) != localMessage )
{
/* The message was converted during processing, this can only happen
when a message sent to an invalid-state object is converted into
a destroy-object message. What we therefore enqueue is a
destroy-object message, but with the messageValue parameter set
to TRUE to indicate that it's a converted destroy message */
PRE( localMessage == MESSAGE_DESTROY );
status = enqueueMessage( localObjectHandle,
&messageHandlingInfo[ MESSAGE_DESTROY ],
MESSAGE_DESTROY, messageDataPtr, TRUE );
}
else
status = enqueueMessage( localObjectHandle, handlingInfoPtr, message,
messageDataPtr, messageValue );
if( cryptStatusError( status ) )
{
/* A message for this object is already present in the queue, defer
processing until later */
MUTEX_UNLOCK( objectTable );
return( ( status == OK_SPECIAL ) ? CRYPT_OK : status );
}
/* While there are more messages for this object present, dequeue them
and dispatch them. Since messages will only be enqueued if
krnlSendMessage() is called recursively, we only dequeue messages for
the current object in this loop. Queued messages for other objects
will be handled at a different level of recursion */
while( getNextMessage( localObjectHandle, &enqueuedMessageData ) )
{
const BOOLEAN isDestroy = \
( ( enqueuedMessageData.message & MESSAGE_MASK ) == MESSAGE_DESTROY );
/* If there's a problem with the object, initiate special processing.
There are two exceptions to this, one is a destroy message sent to
a busy object, the other is a destroy message that started out as
a different type of message (that is, it was converted into a
destroy object message due to the object being in an invalid
state, indicated by the messageValue parameter being set to TRUE
when it's normally zero for a destroy message). Both of these
types are let through */
if( isInvalidObjectState( localObjectHandle ) && \
!( isDestroy && \
( objectInfoPtr->flags & OBJECT_FLAG_BUSY ) || \
( enqueuedMessageData.messageValue == TRUE ) ) )
{
/* If it's a destroy object message being sent to an object in
the process of being created, set the state to signalled and
continue. The object will be destroyed when the caller
notifies the kernel that the init is complete */
if( isDestroy && ( objectInfoPtr->flags & OBJECT_FLAG_NOTINITED ) )
{
objectInfoPtr->flags |= OBJECT_FLAG_SIGNALLED;
status = CRYPT_OK;
}
else
{
/* Remove all further messages for this object and return
to the caller */
dequeueAllMessages( localObjectHandle );
status = getObjectStatusValue( objectInfoPtr->flags );
}
continue;
}
/* Inner precondition: The object is in a valid state or it's a
destroy message to a busy object or a destroy message that was
converted from a different message type */
PRE( !isInvalidObjectState( localObjectHandle ) || \
( isDestroy && \
( objectInfoPtr->flags & OBJECT_FLAG_BUSY ) || \
( enqueuedMessageData.messageValue == TRUE ) ) );
/* Dispatch the message to the object */
status = dispatchMessage( localObjectHandle, &enqueuedMessageData,
objectInfoPtr, aclPtr );
/* If the message is a destroy object message, we have to explicitly
remove it from the object table and dequeue all further messages
for it since the object's message handler can't do this itself.
Since a destroy object message always succeeds but can return an
error code (typically CRYPT_ERROR_INCOMPLETE), we don't treat an
error return as a real error status for the purposes of further
processing */
if( isDestroy )
{
destroyObjectData( localObjectHandle );
dequeueAllMessages( localObjectHandle );
}
else
/* If we ran into a problem, dequeue all further messages for
this object. This causes getNextMessage() to fail and we
drop out of the loop */
if( cryptStatusError( status ) )
dequeueAllMessages( localObjectHandle );
}
/* Unlock the object table to allow access by other threads */
MUTEX_UNLOCK( objectTable );
/* Postcondition: The return status is valid */
POST( ( status >= CRYPT_ENVELOPE_RESOURCE && status <= CRYPT_OK ) || \
cryptArgError( status ) || status == OK_SPECIAL );
return( status );
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -