Esempio n. 1
0
int main(int argc, char **argv)
{
    if (argc < 2) {
        printf("Need .beam file\n");
        return EXIT_FAILURE;
    }
    MappedFile *mapped_file = mapped_file_open_beam(argv[1]);
    if (IS_NULL_PTR(mapped_file)) {
        return EXIT_FAILURE;
    }

    GlobalContext *glb = globalcontext_new();

    const void *startup_beam;
    uint32_t startup_beam_size;
    const char *startup_module_name = argv[1];

    if (avmpack_is_valid(mapped_file->mapped, mapped_file->size)) {
        glb->avmpack_data = mapped_file->mapped;
        glb->avmpack_platform_data = mapped_file;

        if (!avmpack_find_section_by_flag(mapped_file->mapped, 1, &startup_beam, &startup_beam_size, &startup_module_name)) {
            fprintf(stderr, "%s cannot be started.\n", argv[1]);
            mapped_file_close(mapped_file);
            return EXIT_FAILURE;
        }
    } else if (iff_is_valid_beam(mapped_file->mapped)) {
        glb->avmpack_data = NULL;
        glb->avmpack_platform_data = NULL;
        startup_beam = mapped_file->mapped;
        startup_beam_size = mapped_file->size;

    } else {
        fprintf(stderr, "%s is not a BEAM file.\n", argv[1]);
        mapped_file_close(mapped_file);
        return EXIT_FAILURE;
    }

    Module *mod = module_new_from_iff_binary(glb, startup_beam, startup_beam_size);
    if (IS_NULL_PTR(mod)) {
        fprintf(stderr, "Cannot load startup module: %s\n", startup_module_name);
        return EXIT_FAILURE;
    }
    globalcontext_insert_module_with_filename(glb, mod, startup_module_name);
    mod->module_platform_data = NULL;
    Context *ctx = context_new(glb);
    ctx->leader = 1;

    context_execute_loop(ctx, mod, "start", 0);

    printf("Return value: %lx\n", ctx->x[0]);

    context_destroy(ctx);
    globalcontext_destroy(glb);
    module_destroy(mod);
    mapped_file_close(mapped_file);

    return EXIT_SUCCESS;
}
Esempio n. 2
0
File: sys.c Progetto: sdwarak/AtomVM
Module *sys_load_module(GlobalContext *global, const char *module_name)
{
    TRACE("sys_load_module: Going to load: %s\n", module_name);

    const void *beam_module = NULL;
    uint32_t beam_module_size = 0;

    MappedFile *beam_file = NULL;
    if (!(global->avmpack_data && avmpack_find_section_by_name(global->avmpack_data, module_name, &beam_module, &beam_module_size))) {
        beam_file = mapped_file_open_beam(module_name);
        if (UNLIKELY(!iff_is_valid_beam(beam_file->mapped))) {
            fprintf(stderr, "%s is not a valid BEAM file.\n", module_name);
        }
        beam_module = beam_file->mapped;
        beam_module_size = beam_file->size;
    }

    Module *new_module = module_new_from_iff_binary(global, beam_module, beam_module_size);
    if (IS_NULL_PTR(new_module)) {
        return NULL;
    }
    new_module->module_platform_data = beam_file;

    return new_module;
}
Esempio n. 3
0
static void process_console_mailbox(Context *ctx)
{

    Message *msg = mailbox_dequeue(ctx);
    term pid = term_get_tuple_element(msg->message, 0);
    term val = term_get_tuple_element(msg->message, 1);

    int local_process_id = term_to_local_process_id(pid);
    Context *target = globalcontext_get_process(ctx->global, local_process_id);

    char *str = interop_term_to_string(val);
    if (IS_NULL_PTR(str)) {
        free(msg);
        return;
    }

    printf("%s", str);
    free(str);

    //TODO: use globalcontext_get_atom_id(ctx->global, ok_atom);
    int ok_index = globalcontext_insert_atom(ctx->global, ok_atom);
    mailbox_send(target, term_from_atom_index(ok_index));

    free(msg);
}
Esempio n. 4
0
//----------------------------------------------------------//
// CFileManager::Instance
//----------------------------------------------------------//
//-- Description			
//----------------------------------------------------------//
const CFileManager* CFileManager::Instance(void)
{
	if (IS_NULL_PTR(m_pSingleton))
	{
		m_pSingleton = new CFileManager();
	}
	return m_pSingleton;
}
Esempio n. 5
0
//----------------------------------------------------------//
// CPacket::GetMessages
//----------------------------------------------------------//
CPacket::Error::Enum CPacket::GetMessages(TMessageList& tempList)
{
	//-- DataBuffer should have exactly m_HeaderV1.m_nMessages inside it.
	tempList.clear();

	u16 nProcessedMessages = 0;
	CPacketSerializer messageDeserializer(ISerializer::Mode::Deserializing, m_DataBuffer.Buffer(), m_DataBuffer.UsedSize());
	CPacketSerializer::Error::Enum eSerError = CPacketSerializer::Error::Ok;
	
	while ( (CPacketSerializer::Error::Ok == eSerError)
		&& (messageDeserializer.GetOffset() < messageDeserializer.GetSize()) )
	{
		CMessage::Type nMessageType = CMessage::kTypeUnknown;

		if (IS_ZERO(messageDeserializer.SerializeU32(nMessageType, 'type')))
		{
			return Error::Serializer;
		}

		CMessage* pMessage = CMessageFactory::CreateType(nMessageType);
		if (IS_NULL_PTR(pMessage))
		{
			return Error::ProtocolMismatch;
		}

		pMessage->Serialize(messageDeserializer);

		eSerError = messageDeserializer.GetError();
		if (CPacketSerializer::Error::Ok != eSerError)
		{
			return Error::Serializer;
		}

		SysSmartPtr<CMessage> pSmart(pMessage);
		tempList.push_back(pSmart);
		++nProcessedMessages;
	}

	//-- Sanity tests
	//-- messageSerializer should have consumed all its bytes.
	assert(messageDeserializer.GetOffset() == messageDeserializer.GetSize());
	if (messageDeserializer.GetOffset() != messageDeserializer.GetSize())
	{
		return Error::SanityFail;
	}

	//-- We should have processed exactly the right number of messages.
	assert(nProcessedMessages == GetMessageCount());
	if (nProcessedMessages != GetMessageCount())
	{
		return Error::SanityFail;
	}

	return Error::Ok;
}
//----------------------------------------------------------//
// CFileDirectTextReader::GetString
//----------------------------------------------------------//
//-- Description
// Read a string from an open direct access file.
// A string is determined as terminated by a newline
// character or the end of file. Any trailing newline will be
// stripped from the output string.
//----------------------------------------------------------//
IFixedString& CFileDirectTextReader::GetString(IFixedString& strString)
{
	if (IS_TRUE(Validate())
		&& IS_TRUE(IsOpen()) )
	{
		if (IS_NULL_PTR(SysFileIO::Fgets(m_pFile, strString.Buffer(), strString.Size())))
		{
			//-- fgets got nothing. Mirror that in the FixedString.
			strString.Clear();
		}
	}

	return strString;
}
Esempio n. 7
0
static term nif_erlang_open_port_2(Context *ctx, int argc, term argv[])
{
    if (UNLIKELY(argc != 2)) {
        fprintf(stderr, "wrong arity\n");
        abort();
    }

    term port_name = argv[0];
    term opts = argv[1];

    if (!(term_is_tuple(port_name) && term_get_tuple_arity(port_name) == 2) && !term_is_nonempty_list(opts)) {
        fprintf(stderr, "bad args\n");
        abort();
    }

    term t = term_get_tuple_element(port_name, 1);
    char *driver_name = interop_term_to_string(t);
    if (IS_NULL_PTR(driver_name)) {
        int error_index = globalcontext_insert_atom(ctx->global, error_atom);
        if (error_index < 0) {
            abort();
        }
        return term_from_atom_index(error_index);
    }

    Context *new_ctx = NULL;

    if (!strcmp("echo", driver_name)) {
        new_ctx = context_new(ctx->global);
        new_ctx->native_handler = process_echo_mailbox;

    } else if (!strcmp("console", driver_name)) {
        new_ctx = context_new(ctx->global);
        new_ctx->native_handler = process_console_mailbox;
    }

    if (!new_ctx) {
        new_ctx = platform_open_port(ctx->global, driver_name, opts);
    }

    free(driver_name);

    scheduler_make_waiting(ctx->global, new_ctx);

    return term_from_local_process_id(new_ctx->process_id);
}
Esempio n. 8
0
static term binary_to_atom(Context *ctx, int argc, term argv[], int create_new)
{
    if (argc != 2) {
        fprintf(stderr, "binary_to_atom: wrong args count\n");
        abort();
    }

    if (UNLIKELY(argv[1] != term_from_atom_string(ctx->global, latin1_atom))) {
        fprintf(stderr, "binary_to_atom: only latin1 is supported.\n");
        abort();
    }

    char *atom_string = interop_binary_to_string(argv[0]);
    if (IS_NULL_PTR(atom_string)) {
        fprintf(stderr, "Failed to alloc temporary string\n");
        abort();
    }
    int atom_string_len = strlen(atom_string);
    if (UNLIKELY(atom_string_len > 255)) {
        fprintf(stderr, "Too long atom.\n");
        free(atom_string);
        abort();
    }

    AtomString atom = malloc(atom_string_len + 1);
    ((uint8_t *) atom)[0] = atom_string_len;
    memcpy(((char *) atom) + 1, atom_string, atom_string_len);

    unsigned long global_atom_index = atomshashtable_get_value(ctx->global->atoms_table, atom, ULONG_MAX);
    int has_atom = (global_atom_index != ULONG_MAX);

    if (create_new || has_atom) {
        if (!has_atom) {
            global_atom_index = globalcontext_insert_atom(ctx->global, atom);
        } else {
            free((void *) atom);
        }
        return term_from_atom_index(global_atom_index);

    } else {
        free((void *) atom);
        //TODO: error here
        return term_nil();
    }
}
Esempio n. 9
0
int test_modules_execution()
{
    struct Test *test = tests;

    if (chdir("erlang_tests")) {
        return EXIT_FAILURE;
    }

    do {
        printf("-- EXECUTING TEST: %s\n", test->test_file);
        MappedFile *beam_file = mapped_file_open_beam(test->test_file);
        assert(beam_file != NULL);

        GlobalContext *glb = globalcontext_new();
        glb->avmpack_data = NULL;
        glb->avmpack_platform_data = NULL;
        Module *mod = module_new_from_iff_binary(glb, beam_file->mapped, beam_file->size);
        if (IS_NULL_PTR(mod)) {
            fprintf(stderr, "Cannot load startup module: %s\n", test->test_file);
            test++;
            continue;
        }
        globalcontext_insert_module_with_filename(glb, mod, test->test_file);
        Context *ctx = context_new(glb);
        ctx->leader = 1;

        context_execute_loop(ctx, mod, "start", 0);

        int32_t value = term_to_int32(ctx->x[0]);
        if (value != test->expected_value) {
            fprintf(stderr, "\x1b[1;31mFailed test module %s, got value: %i\x1b[0m\n", test->test_file, value);
        }

        context_destroy(ctx);
        globalcontext_destroy(glb);
        module_destroy(mod);
        mapped_file_close(beam_file);

        test++;
    } while (test->test_file);

    return EXIT_SUCCESS;
}
//----------------------------------------------------------//
// CTCPNonblockingConnector::Update
//----------------------------------------------------------//
//-- Description
// Update the connector, opening a socket, calling
// connect(), etc.
// Note that the result contains a Non-blocking
// CTCPConnection.
//----------------------------------------------------------//
CTCPConnector::Result CTCPNonblockingConnector::Update(void)
{
    Result result;
    Error::Enum eError = Error::InProgress;

    switch (m_eState)
    {
    default:
    {
        eError = Error::WrongState;
    }
    break;

    case State::GettingAddrInfo:
    {
        m_pCur = m_pAddrResults;
        m_eState = State::NextAddr;
    }
    break;

    case State::NextAddr:
    {
        if (IS_NULL_PTR(m_pCur))
        {
            eError = Error::NoMoreInfo;
            break;
        }

        m_nSocket = SysSocket::OpenSocket(m_pCur->ai_family, m_pCur->ai_socktype, m_pCur->ai_protocol);
        if (SysSocket::INVALID_SOCK == m_nSocket)
        {
            eError = Error::OpenFail;
            break;
        }

        if (SYS_SOCKET_NO_ERROR != SysSocket::SetNonblocking(m_nSocket, true))
        {
            eError = Error::SetSockOptFail;
            break;
        }

        //-- Success
        switch (SysSocket::Connect(m_nSocket, m_pCur->ai_addr, m_pCur->ai_addrlen))
        {
        case SYS_SOCKET_IN_PROGRESS:
        {
            //-- Expected return value for a non-blocking connect
            m_pollFd.fd = m_nSocket;
            m_eState = State::Connecting;
        }
        break;
        case SYS_SOCKET_NO_ERROR:
        {
            //-- Connected immediately
            eError = Error::Ok;
        }
        break;
        default:
        {
            eError = Error::ConnectFail;
        }
        break;
        }
    }
    break;

    case State::Connecting:
    {
        //-- Wait for select/poll
        if (SysSocket::INVALID_SOCK == m_pollFd.fd)
        {
            break;
        }

        s32 nError = SysSocket::Poll(&m_pollFd, 1, 0);
        if (SYS_SOCKET_ERROR == nError)
        {
            //-- Error occurred in select.
            eError = Error::SelectFail;
            break;
        }

        if (TEST_FLAG(m_pollFd.revents, POLLOUT))
        {
            s32 nVal;
            size_t nValSize = sizeof(nVal);
            s32 nErr = SysSocket::GetSockOpt(m_nSocket, SOL_SOCKET, SO_ERROR, &nVal, &nValSize);
            if (SYS_SOCKET_ERROR == nError)
            {
                //-- Error.
                eError = Error::GetSockOptFail;
                break;
            }

            if (SYS_SOCKET_NO_ERROR == nVal)
            {
                //-- Connected
                eError = Error::Ok;
            }
            else
            {
                //-- Some other kind of error on socket.
                eError = Error::ConnectFail;
            }
        }
        if (TEST_FLAG(m_pollFd.revents, POLLERR))
        {
            //-- Error.
            eError = Error::ConnectFail;
        }
    }
    break;
    }

    switch (eError)
    {
    case Error::InProgress:
    {
        //-- Nothing to do
        result.m_eError = Error::InProgress;
    }
    break;

    case Error::Ok:
    {
        //-- Finished!
        if (SysSocket::INVALID_SOCK != m_nSocket)
        {
            result.m_pConnection = new CTCPConnection(m_nSocket);
        }
        result.m_eError = Error::Ok;

        CleanAddrResults();
        m_eState = State::Connected;
    }
    break;

    case Error::WrongState:
    {
        result.m_eError = Error::WrongState;

        CleanAddrResults();
        CleanSocket();
        m_pollFd.fd = SysSocket::INVALID_SOCK;

        m_eState = State::NotConnected;
    }
    break;

    default:
    {
        //-- Any other kind of error.
        CleanSocket();
        m_pollFd.fd = SysSocket::INVALID_SOCK;

        if (IS_PTR(m_pCur))
        {
            m_pCur = m_pCur->ai_next;

            switch (m_eState)
            {
            case State::NextAddr:
            {
                //-- return error as still 'in progress' instead of actual error.
                result.m_eError = Error::InProgress;
            }
            break;
            case State::Connecting:
            {
                //-- return error as still 'in progress' instead of actual error.
                result.m_eError = Error::InProgress;
                //-- reset state to loop onto next next address
                m_eState = State::NextAddr;
            }
            break;
            default:
            {
                //-- Unexpected state!
                //-- This is a bad failure and will stop the connect process.
                result.m_eError = eError;

                CleanAddrResults();
                m_eState = State::NotConnected;
            }
            break;
            }
        }
        else
        {
            //-- No more addresses to try.
            result.m_eError = eError;

            CleanAddrResults();
            m_eState = State::NotConnected;
        }
    }
    }

    return result;
}
Esempio n. 11
0
File: sys.c Progetto: sdwarak/AtomVM
extern void sys_waitevents(struct ListHead *listeners_list)
{
    struct timespec now;
    clock_gettime(CLOCK_MONOTONIC, &now);

    EventListener *listeners = GET_LIST_ENTRY(listeners_list, EventListener, listeners_list_head);
    EventListener *last_listener = GET_LIST_ENTRY(listeners_list->prev, EventListener, listeners_list_head);

    int min_timeout = INT_MAX;
    int count = 0;

    //first: find maximum allowed sleep time, and count file descriptor listeners
    EventListener *listener = listeners;
    do {
        if (listener->expires) {
            int wait_ms = timespec_diff_to_ms(&listener->expiral_timestamp, &now);
            if (wait_ms <= 0) {
                min_timeout = 0;
            } else if (min_timeout > wait_ms) {
                min_timeout = wait_ms;
            }
        }
        if (listener->fd >= 0) {
            count++;
        }

        listener = GET_LIST_ENTRY(listener->listeners_list_head.next, EventListener, listeners_list_head);
    } while (listener != listeners);

    //second: use either poll or nanosleep
    if (count > 0) {
        struct pollfd *fds = calloc(count, sizeof(struct pollfd));
        if (IS_NULL_PTR(fds)) {
            fprintf(stderr, "Cannot allocate memory for pollfd, aborting.\n");
            abort();
        }
        int poll_fd_index = 0;

        //build pollfd array
        EventListener *listener = listeners;
        do {
            if (listener->fd >= 0) {
                fds[poll_fd_index].fd = listener->fd;
                fds[poll_fd_index].events = POLLIN;
                fds[poll_fd_index].revents = 0;
            }

            poll_fd_index++;

            listener = GET_LIST_ENTRY(listener->listeners_list_head.next, EventListener, listeners_list_head);
        } while (listener != listeners);

        poll(fds, poll_fd_index, min_timeout);

        //check which event happened
        listener = listeners;
        do {
            EventListener *next_listener = GET_LIST_ENTRY(listener->listeners_list_head.next, EventListener, listeners_list_head);
            for (int i = 0; i < poll_fd_index; i++) {
                if ((fds[i].fd == listener->fd) && (fds[i].revents & fds[i].events)) {
                    //it is completely safe to free a listener in the callback, we are going to not use it after this call
                    listener->handler(listener);
                }
            }

            listener = next_listener;
        } while (listener != listeners);

        free(fds);

    //just need to wait for a certain timespan
    } else {
        struct timespec t;
        t.tv_sec = min_timeout / 1000;
        t.tv_nsec = (min_timeout % 1000) * 1000000;

        struct timespec rem;
        int nanosleep_result = nanosleep(&t, &rem);
        while (nanosleep_result == -1) {
            nanosleep_result = nanosleep(&rem, &rem);
        }
    }

    //third: execute handlers for expiered timers
    if (min_timeout != INT_MAX) {
        listener = listeners;
        clock_gettime(CLOCK_MONOTONIC, &now);
        do {
            EventListener *next_listener = GET_LIST_ENTRY(listener->listeners_list_head.next, EventListener, listeners_list_head);
            if (listener->expires) {
                int wait_ms = timespec_diff_to_ms(&listener->expiral_timestamp, &now);
                if (wait_ms <= 0) {
                    //it is completely safe to free a listener in the callback, we are going to not use it after this call
                    listener->handler(listener);
                    //TODO check if one shot
                }
            }

            listener = next_listener;
        } while (listener != last_listener);
    }
}
Esempio n. 12
0
//----------------------------------------------------------//
// CPacket::Serialize
//----------------------------------------------------------//
CPacket::Error::Enum CPacket::Serialize(CPacketSerializer& serializer)
{
	if (ISerializer::Mode::Serializing == serializer.GetMode())
	{
		//-- Serializing
		m_nVersion = Version::Current;

		if (IS_ZERO(serializer.SerializeU8(m_nVersion, 'pktV')))
		{
			return Error::Serializer;
		}

		//-- Serializer must have at least the size of the header in bytes free to proceed
		size_t nUnusedSize = serializer.GetSize() - serializer.GetOffset();
		if (nUnusedSize < GetHeaderSize())
		{
			//-- Not enough bytes in serializer.	
			return Error::Serializer;
		}

		//-- Version::V1
		if ( IS_ZERO(serializer.SerializeU8(m_HeaderV1.m_nFlags, 'flgs'))
			|| IS_ZERO(serializer.SerializeU16(m_HeaderV1.m_nMessages, 'mess')) )
		{
			return Error::Serializer;
		}
	
		if (IS_TRUE(IsEncrypted()))
		{
			size_t nEncodedSize = SysString::Base64EncodedSize(m_DataBuffer.UsedSize());
			if (IS_ZERO(nEncodedSize))
			{
				//-- Failed.
				//-- Something went wrong with the Encode.
				return Error::EncryptionFailed;
			}

			m_HeaderV1.m_nDataSize = nEncodedSize;

			if (IS_ZERO(serializer.SerializeU16(m_HeaderV1.m_nDataSize, 'size')))
			{
				return Error::Serializer;
			}

			//-- We need a spare byte for null terminating the encoded base64 string.
			//-- This is blegh!
			//-- Test for unused space in serializer.
			size_t nUnusedSize = serializer.GetSize() - serializer.GetOffset();
			if (nUnusedSize < ((size_t)m_HeaderV1.m_nDataSize + 1))
			{
				//-- Not enough bytes in serializer.
				return Error::Serializer;
			}

			//-- Notice we do not include the extra byte when we reserve space.
			u8* pReserved = serializer.SerializeReserve(m_HeaderV1.m_nDataSize);
			if (IS_NULL_PTR(pReserved))
			{
				//-- Failed.
				return Error::Serializer;
			}

			//-- Valid encryption key?
			if (SysString::INVALID_KEY == m_Key)
			{
				return Error::EncryptionFailed;
			}

			//-- NOTE: this will actually put a null terminator beyond the end 
			//-- of the pReserved block! But should be ok because we checked 
			//-- if there was room enough in the unused size of the serializer
			//-- for it.
			//-- Whatever gets serialized next will overwrite the null terminator,
			//-- which is ok.
			nEncodedSize = SysString::KeyEncode(
				(s8*)pReserved, 
				m_HeaderV1.m_nDataSize + 1,				
				m_DataBuffer.Buffer(), 
				m_DataBuffer.UsedSize(),
				m_Key);

			if (IS_ZERO(nEncodedSize))
			{
				//-- Failed.
				//-- Something went wrong with the Encode.
				return Error::EncryptionFailed;
			}

			if (IS_NULL_PTR(m_DataBuffer.StripHead(NULL, m_DataBuffer.UsedSize())))
			{
				//-- Failed.
				//-- DataBuffer wasn't full enough
				return Error::DataBufferEmpty;
			}
		}
		else
		{
			//-- Write directly into serializer.
			m_HeaderV1.m_nDataSize = m_DataBuffer.UsedSize();

			if (IS_ZERO(serializer.SerializeU16(m_HeaderV1.m_nDataSize, 'size')))
			{
				return Error::Serializer;
			}

			u8* pReserved = serializer.SerializeReserve(m_HeaderV1.m_nDataSize);
			if (IS_NULL_PTR(pReserved))
			{
				//-- Failed.
				return Error::Serializer;
			}

			if (IS_NULL_PTR(SysMemory::Memcpy(pReserved, m_HeaderV1.m_nDataSize, m_DataBuffer.Buffer(), m_HeaderV1.m_nDataSize)))
			{
				//-- Failed.
				return Error::CopyFailed;
			}

			if (IS_NULL_PTR(m_DataBuffer.StripHead(NULL, m_HeaderV1.m_nDataSize)))
			{
				//-- Failed.
				//-- DataBuffer wasn't full enough
				return Error::DataBufferEmpty;
			}
		}

		//-- DataBuffer should now be empty.
		assert(IS_ZERO(m_DataBuffer.UsedSize()));
		assert(m_HeaderV1.m_nMessages > 0);
		assert(m_HeaderV1.m_nDataSize > 0);
		//-- End.
	}
	else
	{
		//-- Deserializing.
		SysMemory::Memclear(&m_HeaderV1, sizeof(m_HeaderV1));
		m_DataBuffer.Clear();

		//-- Read version number.
		if (IS_ZERO(serializer.SerializeU8(m_nVersion, 'pktV')))
		{
			//-- Failed to read version number.
			return Error::Serializer;
		}

		//-- Serializer must be at least the size of the header in bytes to proceed
		size_t nUnreadSize = serializer.GetSize() - serializer.GetOffset();
		if (nUnreadSize < GetHeaderSize())
		{
			//-- Not enough bytes in serializer.
			return Error::Serializer;
		}

		//-- Read the header
		switch (m_nVersion)
		{
			case Version::V1:
			{
				if ( IS_ZERO(serializer.SerializeU8(m_HeaderV1.m_nFlags, 'flgs'))
					|| IS_ZERO(serializer.SerializeU16(m_HeaderV1.m_nMessages, 'mess'))
					|| IS_ZERO(serializer.SerializeU16(m_HeaderV1.m_nDataSize, 'size')) )
				{
					return Error::Serializer;
				}

				if (Version::Unknown == Validate())
				{
					return Error::ProtocolMismatch;
				}

				u8* pDataSrc = serializer.SerializeReserve(m_HeaderV1.m_nDataSize);
				if (IS_NULL_PTR(pDataSrc))
				{
					//-- Failed.
					return Error::Serializer;
				}

				//-- Is packet encrypted?
				if (IS_TRUE(IsEncrypted()))
				{
					//-- Decrypt packet payload data to DataBuffer
					size_t nDecodedSize = SysString::Base64DecodedSize((const s8*)pDataSrc, m_HeaderV1.m_nDataSize);
					if (IS_ZERO(nDecodedSize))
					{
						//-- Failed.
						//-- Something went wrong with the Decode.
						return Error::EncryptionFailed;
					}
					assert(m_DataBuffer.Size() >= nDecodedSize);

					u8* pDataDest = m_DataBuffer.InsTail(NULL, nDecodedSize);
					if (IS_NULL_PTR(pDataDest))
					{
						//-- Failed.
						//-- DataBuffer is too full.
						return Error::DataBufferFull;
					}
					
					//-- Valid encryption key?
					if (SysString::INVALID_KEY == m_Key)
					{
						return Error::EncryptionFailed;
					}

					nDecodedSize = SysString::KeyDecode(
						pDataDest, 
						nDecodedSize,
						(const s8*)pDataSrc, 
						m_HeaderV1.m_nDataSize,
						m_Key);

					if (IS_ZERO(nDecodedSize))
					{
						//-- Failed.
						//-- Something went wrong with the Decode.
						return Error::EncryptionFailed;
					}
				}
				else
				{
					//-- Read directly into buffer.
					assert(m_DataBuffer.Size() >= m_HeaderV1.m_nDataSize);

					if (IS_NULL_PTR(m_DataBuffer.InsTail(pDataSrc, m_HeaderV1.m_nDataSize)))
					{
						//-- Failed.
						//-- DataBuffer is too full.
						return Error::DataBufferFull;
					}
				}

				//-- DataBuffer should now have exactly m_HeaderV1.m_nMessages inside it.
				//-- End.
			}
			break;
			default:
			{
				//-- Unexpected version
				return Error::UnknownVersion;
			}
			break;
		}
	}

	return Error::Ok;
}