//Set up the test fixture
void setup(void) {
  o = osrf_message_init(CONNECT, 1, 1);
}
示例#2
0
/**
	@brief Either send or enqueue a response to a client, optionally with a completion notice.
	@param ctx Pointer to the method context.
	@param data Pointer to the response, in the form of a jsonObject.
	@param complete Boolean: if true, we will accompany the RESULT message with a STATUS
	message indicating that the response is complete.
	@return Zero if successful, or -1 upon error.

	For an atomic method, add a copy of the response data to a cache within the method
	context, to be sent later.  In this case the @a complete parameter has no effect,
	because we'll send the STATUS message later when we send the cached results.

	If the method is not atomic, translate the message into JSON and append it to a buffer,
	flushing the buffer as needed to avoid overflow.  If @a complete is true, append
	a STATUS message (as JSON) to the buffer and flush the buffer.
*/
static int _osrfAppRespond( osrfMethodContext* ctx, const jsonObject* data, int complete ) {
	if(!(ctx && ctx->method)) return -1;

	if( ctx->method->options & OSRF_METHOD_ATOMIC ) {
		osrfLogDebug( OSRF_LOG_MARK,
			"Adding responses to stash for atomic method %s", ctx->method->name );

		// If we don't already have one, create a JSON_ARRAY to serve as a cache.
		if( ctx->responses == NULL )
			ctx->responses = jsonNewObjectType( JSON_ARRAY );

		// Add a copy of the data object to the cache.
		if ( data != NULL )
			jsonObjectPush( ctx->responses, jsonObjectClone(data) );
	} else {
		osrfLogDebug( OSRF_LOG_MARK,
			"Adding responses to stash for method %s", ctx->method->name );

		if( data ) {
			// If you want to flush the intput buffers for every output message,
			// this is the place to do it.
			//osrf_app_session_queue_wait( ctx->session, 0, NULL );

			// Create an OSRF message
			osrfMessage* msg = osrf_message_init( RESULT, ctx->request, 1 );
			osrf_message_set_status_info( msg, NULL, "OK", OSRF_STATUS_OK );
			osrf_message_set_result( msg, data );

			// Serialize the OSRF message into JSON text
			char* json = jsonObjectToJSON( osrfMessageToJSON( msg ));
			osrfMessageFree( msg );

			// If the new message would overflow the buffer, flush the output buffer first
			int len_so_far = buffer_length( ctx->session->outbuf );
			if( len_so_far && (strlen( json ) + len_so_far + 3 >= ctx->method->bufsize )) {
				if( flush_responses( ctx->session, ctx->session->outbuf ))
					return -1;
			}

			// Append the JSON text to the output buffer
			append_msg( ctx->session->outbuf, json );
			free( json );
		}

		if(complete) {
			// Create a STATUS message
			osrfMessage* status_msg = osrf_message_init( STATUS, ctx->request, 1 );
			osrf_message_set_status_info( status_msg, "osrfConnectStatus", "Request Complete",
				OSRF_STATUS_COMPLETE );

			// Serialize the STATUS message into JSON text
			char* json = jsonObjectToJSON( osrfMessageToJSON( status_msg ));
			osrfMessageFree( status_msg );

			// Add the STATUS message to the output buffer.
			// It's short, so don't worry about avoiding overflow.
			append_msg( ctx->session->outbuf, json );
			free( json );

			// Flush the output buffer, sending any accumulated messages.
			if( flush_responses( ctx->session, ctx->session->outbuf ))
				return -1;
		}
	}

	return 0;
}
/**
	@brief Acting as a client, process an incoming osrfMessage.
	@param session Pointer to the osrfAppSession to which the message pertains.
	@param msg Pointer to the osrfMessage.

	What we do with the message depends on the combination of message type and status code:
	- If it's a RESULT message, add it to the message queue of the appropriate app session,
	to be handled later.
	- If it's a STATUS message, handle it according to its status code and return NULL --
	unless it has an unexpected status code, in which case add it to the message queue of
	the appropriate app session, to be handled later.
*/
static void _do_client( osrfAppSession* session, osrfMessage* msg ) {
	if(session == NULL || msg == NULL)
		return;

	if( msg->m_type == STATUS ) {

		switch( msg->status_code ) {

			case OSRF_STATUS_OK:
				// This combination of message type and status code comes
				// only from the router, in response to a CONNECT message.
				osrfLogDebug( OSRF_LOG_MARK, "We connected successfully");
				session->state = OSRF_SESSION_CONNECTED;
				osrfLogDebug( OSRF_LOG_MARK,  "State: %x => %s => %d", session,
						session->session_id, session->state );
				osrfMessageFree(msg);
				break;

			case OSRF_STATUS_COMPLETE:
				osrf_app_session_set_complete( session, msg->thread_trace );
				osrfMessageFree(msg);
				break;

			case OSRF_STATUS_CONTINUE:
				osrf_app_session_request_reset_timeout( session, msg->thread_trace );
				osrfMessageFree(msg);
				break;

			case OSRF_STATUS_REDIRECTED:
				osrf_app_session_reset_remote( session );
				session->state = OSRF_SESSION_DISCONNECTED;
				osrf_app_session_request_resend( session, msg->thread_trace );
				osrfMessageFree(msg);
				break;

			case OSRF_STATUS_EXPFAILED:
				osrf_app_session_reset_remote( session );
				session->state = OSRF_SESSION_DISCONNECTED;
				osrfMessageFree(msg);
				break;

			case OSRF_STATUS_TIMEOUT:
				osrf_app_session_reset_remote( session );
				session->state = OSRF_SESSION_DISCONNECTED;
				osrf_app_session_request_resend( session, msg->thread_trace );
				osrfMessageFree(msg);
				break;

			default:
			{
				/* Replace the old message with a new one */
				osrfMessage* new_msg = osrf_message_init( 
						RESULT, msg->thread_trace, msg->protocol );
				osrf_message_set_status_info( new_msg,
						msg->status_name, msg->status_text, msg->status_code );
				osrfLogWarning( OSRF_LOG_MARK, "The stack doesn't know what to do with "
						"the provided message code: %d, name %s. Passing UP.",
						msg->status_code, msg->status_name );
				new_msg->is_exception = 1;
				osrf_app_session_set_complete( session, msg->thread_trace );
				osrfLogDebug( OSRF_LOG_MARK, 
						"passing client message %d / session %s to app handler",
						msg->thread_trace, session->session_id );
				osrfMessageFree(msg);
				// Enqueue the new message to be processed later
				osrf_app_session_push_queue( session, new_msg );
				break;
			} // end default
		} // end switch

	} else if( msg->m_type == RESULT ) {
		osrfLogDebug( OSRF_LOG_MARK, "passing client message %d / session %s to app handler",
					  msg->thread_trace, session->session_id );
		// Enqueue the RESULT message to be processed later
		osrf_app_session_push_queue( session, msg );

	}

	return;
}
示例#4
0
/**
	@brief Translate a jsonObject into a single osrfMessage.
	@param obj Pointer to the jsonObject to be translated.
	@return Pointer to a newly created osrfMessage.

	It is assumed that @a obj is non-NULL and points to a valid representation of a message.
	For a description of the expected structure of this representations, see osrfMessageToJSON().

	The calling code is responsible for freeing the osrfMessage by calling osrfMessageFree().
*/
static osrfMessage* deserialize_one_message( const jsonObject* obj ) {

	// Get the message type.  If it isn't present, default to CONNECT.
	const jsonObject* tmp = jsonObjectGetKeyConst( obj, "type" );

	enum M_TYPE type = CONNECT;
	const char* t = jsonObjectGetString( tmp );
	if( t ) {

		if(      !strcmp( t, "CONNECT"    ))   type = CONNECT;
		else if( !strcmp( t, "DISCONNECT" ))   type = DISCONNECT;
		else if( !strcmp( t, "STATUS"     ))   type = STATUS;
		else if( !strcmp( t, "REQUEST"    ))   type = REQUEST;
		else if( !strcmp( t, "RESULT"     ))   type = RESULT;
	}

	// Get the thread trace, defaulting to zero.
	int trace = 0;
	tmp = jsonObjectGetKeyConst( obj, "threadTrace" );
	if( tmp ) {
		const char* tt = jsonObjectGetString( tmp );
		if( tt ) {
			trace = atoi( tt );
		}
	}

	// Get the protocol, defaulting to zero.
	int protocol = 0;
	tmp = jsonObjectGetKeyConst( obj, "protocol" );
	if(tmp) {
		const char* proto = jsonObjectGetString(tmp);
		if( proto ) {
			protocol = atoi( proto );
		}
	}

	// Now that we have the essentials, create an osrfMessage
	osrfMessage* msg = osrf_message_init( type, trace, protocol );

	// Update current_locale with the locale of the message
	// (or set it to NULL if not specified)
	tmp = jsonObjectGetKeyConst( obj, "locale" );
	if(tmp && ( msg->sender_locale = jsonObjectToSimpleString(tmp))) {
		if ( current_locale ) {
			if( strcmp( current_locale, msg->sender_locale ) ) {
				free( current_locale );
				current_locale = strdup( msg->sender_locale );
			} // else they're the same already, so don't replace one with the other
		} else
			current_locale = strdup( msg->sender_locale );
	} else {
		if ( current_locale ) {
			free( current_locale );
			current_locale = NULL;
		}
	}

	tmp = jsonObjectGetKeyConst( obj, "payload" );
	if(tmp) {
		// Get method name and parameters for a REQUEST
		const jsonObject* tmp0 = jsonObjectGetKeyConst(tmp,"method");
		const char* tmp_str = jsonObjectGetString(tmp0);
		if(tmp_str)
			msg->method_name = strdup(tmp_str);

		tmp0 = jsonObjectGetKeyConst(tmp,"params");
		if(tmp0) {
			// Note that we use jsonObjectDecodeClass() instead of
			// jsonObjectClone().  The classnames are already decoded,
			// but jsonObjectDecodeClass removes the decoded classnames.
			msg->_params = jsonObjectDecodeClass( tmp0 );
			if(msg->_params && msg->_params->type == JSON_NULL)
				msg->_params->type = JSON_ARRAY;
		}

		// Get status fields for a RESULT or STATUS
		if(tmp->classname)
			msg->status_name = strdup(tmp->classname);

		tmp0 = jsonObjectGetKeyConst(tmp,"status");
		tmp_str = jsonObjectGetString(tmp0);
		if(tmp_str)
			msg->status_text = strdup(tmp_str);

		tmp0 = jsonObjectGetKeyConst(tmp,"statusCode");
		if(tmp0) {
			tmp_str = jsonObjectGetString(tmp0);
			if(tmp_str)
				msg->status_code = atoi(tmp_str);
			if(tmp0->type == JSON_NUMBER)
				msg->status_code = (int) jsonObjectGetNumber(tmp0);
		}

		// Get the content for a RESULT
		tmp0 = jsonObjectGetKeyConst(tmp,"content");
		if(tmp0) {
			// Note that we use jsonObjectDecodeClass() instead of
			// jsonObjectClone().  The classnames are already decoded,
			// but jsonObjectDecodeClass removes the decoded classnames.
			msg->_result_content = jsonObjectDecodeClass( tmp0 );
		}

	}

	return msg;
}