

//_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
//_/_/
//_/_/  This file is part of CMSDK version 2.1.1.260726 (26 July 2026)
//_/_/  
//_/_/  developed by
//_/_/  
//_/_/  Communicative Machines Ltd. 
//_/_/    http://cmlabs.com/
//_/_/  Copyright (c) 2026
//_/_/  
//_/_/  in collaboration with 
//_/_/  
//_/_/  Icelandic Institute for Intelligent Machines ses
//_/_/    Menntavegur 1
//_/_/    101 Reykjavik
//_/_/    ICELAND
//_/_/    http://www.iiim.is/
//_/_/
//_/_/  and is released under the following
//_/_/  
//_/_/  EXTENDED BSD License
//_/_/
//_/_/  Redistribution and use in source and binary forms, with or without
//_/_/  modification, is permitted provided that the following conditions 
//_/_/  are met:
//_/_/
//_/_/  - Redistributions of source code must retain the above copyright 
//_/_/    and collaboration notice, this list of conditions and the following 
//_/_/    disclaimer.
//_/_/
//_/_/  - Redistributions in binary form must reproduce the above copyright 
//_/_/    notice, this list of conditions and the following disclaimer in the 
//_/_/    documentation and/or other materials provided with the distribution.
//_/_/
//_/_/  - Neither the name of its copyright holders nor the names of its 
//_/_/    contributors may be used to endorse or promote products derived from 
//_/_/    this software without specific prior written permission.
//_/_/
//_/_/  - CADIA Clause: The license granted in and to the software under this 
//_/_/    agreement is a limited-use license. The software may not be used in 
//_/_/    furtherance of: (i) intentionally causing bodily injury or severe 
//_/_/    emotional harm to any person; (ii) invading the personal privacy or 
//_/_/    violating the human rights of any person; or (iii) committing or 
//_/_/    preparing for any act of war. 
//_/_/
//_/_/  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
//_/_/  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
//_/_/  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 
//_/_/  PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 
//_/_/  OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
//_/_/  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
//_/_/  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
//_/_/  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 
//_/_/  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 
//_/_/  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 
//_/_/  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//_/_/
//_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
/*! @file MemoryRequestConnection.h
    @brief Client-side endpoint of the named shared-memory request/reply service.
    @ingroup Memory

    A MemoryRequestServer creates a named segment with a RequestServerHeader, a request-
    status table and per-connection queue areas. Any process connects by name with a
    MemoryRequestConnection, then either issues requests (makeRequest/waitForRequestReply)
    or serves them (waitForRequest/replyToRequest). Replies that arrive out of order are
    held in a local replyCache keyed by request id.

    @warning Shared-memory layouts; changing any struct here requires a full rebuild of
    all binaries (`make clean && make`) — see MemoryManager.h for the ABI warning. */

#if !defined(_MEMORYREQUESTCONNECTION_H_)
#define _MEMORYREQUESTCONNECTION_H_

#include "MemoryRequestQueues.h"

namespace cmlabs {

/*! Server status value: segment initialised and accepting connections. */
#define MEMORYREQUESTSERVER_INIT	1


/*! @brief Header of a request-server segment: identity, limits and layout parameters.
    Followed in memory by the request-status map and maxConnectionCount connection areas
    of eachConnectionSize bytes (RequestConnectionHeader + queues).
    @warning Shared-memory layout; see MemoryManager.h for the ABI/rebuild warning. */
struct RequestServerHeader {
	uint32 size;
	uint32 cid;
	uint64 createdTime;
	uint64 lastUpdateTime;
	char name[256];
	uint16 status;
	uint32 maxConnectionCount;
	uint32 eachConnectionSize;
	uint32 maxQueueSize;
	uint32 maxRequestCount;
};

/*! @brief Header of one client connection area within a request-server segment.
    @warning Shared-memory layout; see MemoryManager.h for the ABI/rebuild warning. */
struct RequestConnectionHeader {
	uint32 size;
	uint32 conid;
	uint64 createdTime;
	uint64 lastUpdateTime;
	uint16 status;
};

/*! @brief Client endpoint connected to a named shared-memory request server.
    @ingroup Memory
    One instance per client; not shareable across threads without external locking (it
    keeps per-connection cursors and a reply cache). All returned DataMessages are heap
    copies owned by the caller. Wait calls block up to @a ms milliseconds.
    @code
    MemoryRequestConnection con;
    con.connect("psyclone.requests");
    uint64 id = con.makeRequest(msg);
    DataMessage* reply = con.waitForRequestReply(id, 1000); // 1 s timeout
    if (reply) { ...; delete reply; }
    con.shutdown();
    @endcode */
class MemoryRequestConnection {
public:
	MemoryRequestConnection();
	~MemoryRequestConnection();

	/*! Attach to the named server segment and claim a connection slot.
	    @param memoryName Global name chosen by the server. @return true on success. */
	bool connect(const char* memoryName);
	bool shutdown();	/*!< Release the connection slot and detach. @return true on success. */

	/*! Submit a request to the server. @param msg Request (copied; caller keeps ownership).
	    @return Request id, 0 on failure. */
	uint64 makeRequest(DataMessage* msg);
	/*! Query a request's status. @return MEMORYREQUEST_* value; timestamps via out-params. */
	uint16 getRequestStatus(uint64 id, uint64& createdTime, uint64& lastUpdateTime);
	/*! Wait for the reply to this connection's most recent request. @param ms Timeout in ms.
	    @return Caller-owned reply or NULL on timeout. */
	DataMessage* waitForRequestReply(uint32 ms);

	/*! Wait for the reply to request @a id (out-of-order replies are cached). @param id Request id to wait for. @param ms Timeout in ms.
	    @return Caller-owned reply or NULL on timeout. */
	DataMessage* waitForRequestReply(uint64 id, uint32 ms);

	/*! Server side: wait for the next incoming request. @param ms Timeout in ms.
	    @return Caller-owned request or NULL on timeout. */
	DataMessage* waitForRequest(uint32 ms);
	bool setRequestStatus(uint64 id, uint16 status);	/*!< Server side: advance a request's status. @return true on success. */
	bool replyToRequest(uint64 id, DataMessage* msg);	/*!< Server side: send the reply for @a id (copied). @return true on success. */

private:
	RequestServerHeader* serverHeader;		/*!< Mapped server header (not owned). */
	RequestConnectionHeader* conHeader;		/*!< This connection's area header (not owned). */
	char* queueHeader;						/*!< This connection's queue region. */
	char* requestHeader;					/*!< The server's request-status map region. */

	std::map<uint64, DataMessage*> replyCache;	/*!< Replies received while waiting for another id (owned; deleted on destruction). */

	uint32 conID;				/*!< This connection's slot id. */
	bool oneWaitingForQueue;	/*!< True while a thread is blocked in waitForQueue(). */
	
	utils::Mutex* mutex;		/*!< Guards connection state and the reply cache (owned). */
	utils::Event cacheEvent;	/*!< Signalled when a reply is added to the cache. */

	char* getQueueHeader(uint32 otherConID);	/*!< @return Queue region of connection @a otherConID. */
	DataMessage* waitForQueue(uint32 ms);		/*!< Block for the next message on our queue. @return Caller-owned copy or NULL. */
};

} // namespace cmlabs

#endif //_MEMORYREQUESTCONNECTION_H_

