2 * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
23 * @APPLE_LICENSE_HEADER_END@
25 Change History (most recent first):
28 Revision 1.1 2004/01/30 02:35:13 bradley
29 Rendezvous Message Exchange implementation for DNS-SD IPC on Windows.
33 //---------------------------------------------------------------------------------------------------------------------------
34 /*! @header RMxCommon.h
36 @abstract Common code between the RMxClient and RMxServer.
40 This handles establishing and accepting connections, the underying message sending and receiving, portable data
41 packing an unpacking, and shared utility routines.
44 #ifndef __RMx_COMMON__
45 #define __RMx_COMMON__
47 #include "CommonServices.h"
48 #include "DebugServices.h"
55 #pragma mark == Documentation ==
58 //---------------------------------------------------------------------------------------------------------------------------
61 @abstract Rendezvous Message Exchange (RMx) protocol.
68 All multi-byte data types are transmitted in network byte order (i.e. big endian).
70 Data types requiring the use of specific values (e.g. opcodes) are typedef'd to an abstract type. Data types used
71 in this manner can be easily searched to determine the appropriate values for the data type. Modern development
72 environments can jump directly to a type and therefore the appropriate constants, which speeds up development.
77 All data types and related constants are named to make it easy to associate them. The general scheme is:
81 <type> Describes the data type (e.g. "OpCode" is used for operation codes).
83 For example: RMxOpCode
85 Constants: kRMx<type><name>
87 <type> Describes the data type (e.g. "OpCode" is used for operation codes in RMx messages).
88 <name> Symbolic name for the constant (e.g. "Browse" for browse messages).
90 For example: kRMxOpCodeBrowse
92 These conventions make it easier for users to associate data types with their values and to find places where
93 these data types and constants are used. You can always search for the base portion of symbolic name (e.g.
94 "RMxOpCode" in kRMxOpCodeBrowse) and find all the data types and constants associated with it. Modern
95 development environments also allow you to jump directly to the data type or constant.
100 All data exchanged between client and server is encapsulated in packets of a specific format. There is a
101 generic header followed by an optional, opcode-specific data section:
104 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
105 0 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
107 4 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
109 8 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
111 12 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
113 16 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
115 20 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
117 24 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
118 | data ("size" octets) |
122 n +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
124 The packet format uses implicit typing, which means the sender and receiver must know the types and ordering of the
125 data based on the opcode of the message. There are standard primitive data types defined that all data structures
128 Byte - 8-bit value. Uses the "b" pack/unpack format specifier.
129 Half-Word - 16-bit value. Uses the "h" pack/unpack format specifier.
130 Word - 32-bit value. Uses the "w" pack/unpack format specifier.
131 String - UTF-8 string, null-terminated. Uses the "s" pack/unpack format specifier.
132 Raw Bytes - 32-bit length-prefixed block of data. Uses the "n" pack/unpack format specifier.
134 The String and Raw Byte data types are designed to support directly referencing the raw packet data without
135 copying them into a temporary buffer for efficiency, easy of use, and to reduce the possibility of resource
136 leaks. The String data type contains a null terminator in the packet data so it can be treated as a normal
137 C-style string (e.g. strcpy works on it). The Raw Bytes data type can be used via a pointer and size. The data
138 packing and unpacking routines are designed around the packet format to allow for efficient packet handling.
143 The RMx protocol is a TCP-based client/server protocol. The server listens on a well-known TCP port. The client
144 connects to the server port and a session of message exchange begins. The client drives the session by sending
145 the initial message describing the action it wants performed by the server. The server performs operations
146 requested by the client and asynchronously sends reply messages as specified by the type of request.
148 The general operation of the RMx server is as follows:
150 1) Initialize server (set up synchronization support, etc.).
151 2) Run server by creating socket(s) for listening and wait until a connection is accepted.
152 3) If a connection is accepted:
153 3a) Accept session (allocate, link into session list, create session thread, etc.).
155 The general operation of the RMx client is as follows:
157 1) Initialize client (set up synchronization support, etc.).
158 2) Start a session to the server.
160 The general operation of the RMx session thread (used by the client and server) is as follows:
162 1) Initialize session (set up synchronization support, etc.).
163 2) Wait for a message to be received.
164 3) If a message is received:
165 3a) Process the message.
169 #pragma mark == Versions ==
172 //---------------------------------------------------------------------------------------------------------------------------
173 /*! @typedef kRMxCurrentVersion
175 @abstract Current version of the RMx implementation.
178 #define kRMxCurrentVersion NumVersionBuild( 1, 0, 0, kVersionStageFinal, 0 )
180 //---------------------------------------------------------------------------------------------------------------------------
181 /*! @typedef kRMxOldestClientVersion
183 @abstract Oldest version of the RMx client that works with this server.
186 #define kRMxOldestClientVersion NumVersionBuild( 1, 0, 0, kVersionStageFinal, 0 )
188 //---------------------------------------------------------------------------------------------------------------------------
189 /*! @typedef kRMxOldestServerVersion
191 @abstract Oldest version of the RMx server that works with this client.
194 #define kRMxOldestServerVersion NumVersionBuild( 1, 0, 0, kVersionStageFinal, 0 )
197 #pragma mark == General ==
200 //---------------------------------------------------------------------------------------------------------------------------
201 /*! @defined kRMxServerPort
203 @abstract TCP port of DNS-SD server in host byte order.
206 #define kRMxServerPort 5354
207 #define kRMxServerPortString "5354"
209 //---------------------------------------------------------------------------------------------------------------------------
210 /*! @defined kRMxClientTimeout
212 @abstract Default client timeout.
215 #define kRMxClientTimeout ( 5 * 1000 ) // 5 seconds
217 //---------------------------------------------------------------------------------------------------------------------------
218 /*! @defined kDNSRecordIndexDefault
220 @abstract Record index for the default TXT record.
223 #define kDNSRecordIndexDefaultTXT 0
225 //---------------------------------------------------------------------------------------------------------------------------
228 @abstract State of the RMx engine.
230 @constant kRMxStateInvalid Not in a valid state.
231 @constant kRMxStateStop Stopped.
232 @constant kRMxStateRun Running.
243 //---------------------------------------------------------------------------------------------------------------------------
246 @abstract Global state of the RMx engine.
249 extern RMxState gRMxState
;
251 //---------------------------------------------------------------------------------------------------------------------------
254 @abstract Global state change event associated with the RMx engine.
257 extern HANDLE gRMxStateChangeEvent
;
259 //---------------------------------------------------------------------------------------------------------------------------
260 /*! @function RMxInitialize
262 @abstract Initializes the RMx engine.
265 OSStatus
RMxInitialize( void );
267 //---------------------------------------------------------------------------------------------------------------------------
268 /*! @function RMxFinalize
270 @abstract Finalizes the RMx engine.
273 void RMxFinalize( void );
275 //---------------------------------------------------------------------------------------------------------------------------
276 /*! @function RMxLock
278 @abstract Locks the RMx engine.
281 void RMxLock( void );
283 //---------------------------------------------------------------------------------------------------------------------------
284 /*! @function RMxUnlock
286 @abstract Unlocks the RMx engine.
289 void RMxUnlock( void );
292 #pragma mark == Messages ==
295 //---------------------------------------------------------------------------------------------------------------------------
296 /*! @typedef RMxSignature
298 @abstract Signature for RMx messages.
300 @constant kRMxSignatureVersion1 Version 1 message.
303 typedef uint32_t RMxSignature
;
305 #define kRMxSignatureVersion1 0x524D7831 // 'RMx1' Version 1 message.
307 //---------------------------------------------------------------------------------------------------------------------------
308 /*! @typedef RMxFlags
310 @abstract Flags for RMx messages.
312 @constant kRMxFlagsNone No flags.
315 typedef uint32_t RMxFlags
;
317 #define kRMxFlagsNone 0
319 //---------------------------------------------------------------------------------------------------------------------------
320 /*! @typedef RMxOpCode
322 @abstract Operation code for RMx messages.
324 @constant kRMxOpCodeInvalid Invalid message.
325 @constant kRMxOpCodeCheckVersion DNSServiceCheckVersion message.
326 @constant kRMxOpCodeCopyProperty DNSServiceCopyProperty message.
327 @constant kRMxOpCodeEnumerateDomains DNSServiceEnumerateDomains message.
328 @constant kRMxOpCodeRegister DNSServiceRegister message.
329 @constant kRMxOpCodeAddRecord DNSServiceAddRecord message.
330 @constant kRMxOpCodeUpdateRecord DNSServiceUpdateRecord message.
331 @constant kRMxOpCodeRemoveRecord DNSServiceRemoveRecord message.
332 @constant kRMxOpCodeBrowse DNSServiceBrowse message.
333 @constant kRMxOpCodeResolve DNSServiceResolve message.
334 @constant kRMxOpCodeCreateConnection DNSServiceCreateConnection message.
335 @constant kRMxOpCodeRegisterRecord DNSServiceRegisterRecord message.
336 @constant kRMxOpCodeQueryRecord DNSServiceQueryRecord message.
337 @constant kRMxOpCodeReconfirmRecord DNSServiceReconfirmRecord message.
340 typedef uint32_t RMxOpCode
;
342 #define kRMxOpCodeInvalid 0
344 #define kRMxOpCodeCheckVersion 10
345 // Request: <w:clientCurrentVersion> <w:clientOldestClientVersion> <w:clientOldestServerVersion>
346 // Reply: <w:errorCode> <w:serverCurrentVersion> <w:serverOldestClientVersion> <w:serverOldestServerVersion>
348 #define kRMxOpCodeCopyProperty 11
349 // Request: <w:propertyCode>
350 // Reply: <w:errorCode> <w:propertyCode> <n:propertyData>
352 #define kRMxOpCodeEnumerateDomains 100
353 // Request: <w:flags> <w:interfaceIndex>
354 // Reply: <w:flags> <w:interfaceIndex> <w:errorCode> <s:domain>
356 #define kRMxOpCodeRegister 200
357 // Request: <w:flags> <w:interfaceIndex> <s:name> <s:type> <s:domain> <s:host> <h:port> <n:txt>
358 // Reply: <w:flags> <w:errorCode> <s:name> <s:type> <s:domain>
360 #define kRMxOpCodeAddRecord 201
361 // Request: <w:id> <w:flags> <h:rrType> <n:rrData> <w:ttl>
364 #define kRMxOpCodeUpdateRecord 202
365 // Request: <w:id> <w:flags> <n:rrData> <w:ttl>
368 #define kRMxOpCodeRemoveRecord 203
369 // Request: <w:id> <w:flags>
372 #define kRMxOpCodeBrowse 300
373 // Request: <w:flags> <w:interfaceIndex> <s:type> <s:domain>
374 // Reply: <w:flags> <w:interfaceIndex> <w:errorCode> <s:name> <s:type> <s:domain>
376 #define kRMxOpCodeResolve 400
377 // Request: <w:flags> <w:interfaceIndex> <s:name> <s:type> <s:domain>
378 // Reply: <w:flags> <w:interfaceIndex> <w:errorCode> <s:fullName> <n:addr> <s:hostName> <h:port> <n:txtRecord>
380 #define kRMxOpCodeCreateConnection 500
384 #define kRMxOpCodeRegisterRecord 510
385 // Request: <w:flags> <w:interfaceIndex> <s:name> <h:rrType> <h:rrClass> <n:rrData> <w:ttl>
386 // Reply: <w:flags> <w:errorCode> <w:recordID>
388 #define kRMxOpCodeQueryRecord 511
389 // Request: <w:flags> <w:interfaceIndex> <s:name> <h:rrType> <h:rrClass>
390 // Reply: <w:flags> <w:interfaceIndex> <w:errorCode> <s:name> <h:rrType> <h:rrClass> <n:rrData> <w:ttl>
392 #define kRMxOpCodeReconfirmRecord 512
393 // Request: <w:flags> <w:interfaceIndex> <s:name> <h:rrType> <h:rrClass> <n:rrData>
396 //---------------------------------------------------------------------------------------------------------------------------
397 /*! @typedef RMxMessageCallBack
399 @abstract Callback function for a message.
402 typedef struct RMxMessage RMxMessage
;
404 typedef void ( *RMxMessageCallBack
)( RMxMessage
*inMessage
);
406 //---------------------------------------------------------------------------------------------------------------------------
407 /*! @typedef RMxSessionRef
409 @abstract References to a session.
412 typedef struct RMxSession
* RMxSessionRef
;
414 //---------------------------------------------------------------------------------------------------------------------------
415 /*! @struct RMxMessage
417 @abstract RMx message.
419 @field signature Signature identifying message as an RMx message (and for future versioning).
420 @field opcode Operation code of the message.
421 @field flags Flags for the message.
422 @field xid Transaction ID. WARNING: Must be unique within execution environment (e.g. process).
423 @field status Status of the message (used to return error replies).
425 @field sendSize Size of data to send.
426 @field sendData Data to send.
427 @field recvSize Size of received data.
428 @field recvData Received data.
430 @field context Context for the completion callback (specified when session started).
431 @field session Session where the message is sent/received.
433 @field bufferSize PRIVATE: Size of entire message buffer or 0 if message not constructed.
434 @field buffer PRIVATE: Ptr to entire message buffer or NULL if message not constructed.
435 @field storage PRIVATE: Local storage for small messages.
437 @constant kRMxMessageSynchronous Meta-message indicating operation should be performed synchronously.
438 @constant kRMxMessageHeaderSize Size of the header section of an RMx message packet.
439 @constant kRMxMessageInlineBufferSize Size of the inline message buffer.
443 Meanings of the field descriptions:
445 PRIVATE - Indicates field is private and should not be touched.
446 IN - Input field that must be set up before passing the message to RMx.
447 OUT - Output field that whose value on input will be ignore and replaced with a new value on completion.
449 When a message is passed to RMx, the message becomes the ownership of RMx until completion of the message.
450 No fields of the messages should be touched while a message is in use by RMx.
452 When sending messages asynchronously, the underlying storage for the message must be valid for the duration
453 of the message. This means stack-based storage cannot be for asynchronous messages because when the function
454 that allocated the stack-based variable returns, the message storage will go out of scope and become invalid.
457 #define kRMxMessageHeaderSize 24 // <w:signature> <w:opcode> <w:flags> <w:xid> <w:status> <w:size>
458 #define kRMxMessageInlineBufferSize 1024
460 check_compile_time( kRMxMessageHeaderSize
<= kRMxMessageInlineBufferSize
);
464 RMxSignature signature
;
476 RMxSessionRef session
;
478 // PRIVATE (internal use only)
482 uint8_t storage
[ kRMxMessageInlineBufferSize
];
485 //---------------------------------------------------------------------------------------------------------------------------
486 /*! @function RMxMessageInitialize
488 @abstract Initializes an RMx message structure. Must be called before the message structure can be used.
491 void RMxMessageInitialize( RMxMessage
*inMessage
);
493 //---------------------------------------------------------------------------------------------------------------------------
494 /*! @function RMxMessageRelease
496 @abstract Releases the resources used by an RMx message.
499 void RMxMessageRelease( RMxMessage
*inMessage
);
502 #pragma mark == Sessions ==
505 //---------------------------------------------------------------------------------------------------------------------------
506 /*! @typedef RMxSessionFlags
508 @abstract Session flags.
510 @constant kRMxSessionFlagsNone No flags.
511 @constant kRMxSessionFlagServer Session is operating in server mode (replying to requests).
512 @constant kRMxSessionFlagsNoThread Do not create a thread to process messages (i.e. one-shot sync session).
513 @constant kRMxSessionFlagsThreadDone Thread is no longer active.
514 @constant kRMxSessionFlagsNoClose Do not close the session when the thread exits.
517 typedef uint32_t RMxSessionFlags
;
519 #define kRMxSessionFlagsNone 0
520 #define kRMxSessionFlagsServer ( 1 << 0 )
521 #define kRMxSessionFlagsNoThread ( 1 << 1 )
522 #define kRMxSessionFlagsThreadDone ( 1 << 2 )
523 #define kRMxSessionFlagsNoClose ( 1 << 3 )
525 //---------------------------------------------------------------------------------------------------------------------------
526 /*! @struct RMxSession
528 @abstract Data structure for a session.
531 typedef struct RMxSession RMxSession
;
535 RMxSessionFlags flags
;
542 HANDLE waitHandles
[ 3 ];
545 RMxMessageCallBack callback
;
547 uint8_t * messageRecvBuffer
;
548 uint8_t * messageRecvBufferPtr
;
549 int messageRecvRemaining
;
550 bool messageRecvHeaderDone
;
553 //---------------------------------------------------------------------------------------------------------------------------
554 /*! @function RMxSessionOpen
556 @abstract Opens a session and optionally sends a formatted message.
561 const char * inServer
,
562 RMxSessionFlags inFlags
,
564 RMxMessageCallBack inCallBack
,
566 RMxSessionRef
* outSession
,
567 RMxOpCode inMessageOpCode
,
568 const char * inMessageFormat
,
571 //---------------------------------------------------------------------------------------------------------------------------
572 /*! @function RMxSessionClose
574 @abstract Closes a session.
577 OSStatus
RMxSessionClose( RMxSessionRef inSession
, OSStatus inReason
);
579 //---------------------------------------------------------------------------------------------------------------------------
580 /*! @function RMxSessionSendMessage
582 @abstract Sends a formatted message.
585 OSStatus
RMxSessionSendMessage( RMxSessionRef inSession
, RMxOpCode inOpCode
, OSStatus inStatus
, const char *inFormat
, ... );
587 //---------------------------------------------------------------------------------------------------------------------------
588 /*! @function RMxSessionRecvMessage
590 @abstract Synchronously receives a message.
593 OSStatus
RMxSessionRecvMessage( RMxSessionRef inSession
, DWORD inTimeout
);
596 #pragma mark == Utilities ==
599 //---------------------------------------------------------------------------------------------------------------------------
600 /*! @function RMxCheckVersion
602 @abstract Compares client and server version information and returns if they are compatible.
607 uint32_t inClientCurrentVersion
, uint32_t inClientOldestClientVersion
, uint32_t inClientOldestServerVersion
,
608 uint32_t inServerCurrentVersion
, uint32_t inServerOldestClientVersion
, uint32_t inServerOldestServerVersion
);
610 //---------------------------------------------------------------------------------------------------------------------------
611 /*! @function RMxPackedSize
613 @abstract Determines the number of bytes required to pack data using the specified format string and arguments.
616 OSStatus
RMxPackedSize( size_t *outSize
, const char *inFormat
, ... );
618 //---------------------------------------------------------------------------------------------------------------------------
619 /*! @function RMxPackedSizeVAList
621 @abstract Determines the number of bytes required to pack data using the format string and argument list.
624 OSStatus
RMxPackedSizeVAList( size_t *outSize
, const char *inFormat
, va_list inArgs
);
626 //---------------------------------------------------------------------------------------------------------------------------
627 /*! @function RMxPack
629 @abstract Packs data into a buffer using the format string and arguments.
632 OSStatus
RMxPack( void *inBuffer
, size_t inMaxSize
, size_t *outSize
, const char *inFormat
, ... );
634 //---------------------------------------------------------------------------------------------------------------------------
635 /*! @function RMxPackVAList
637 @abstract Packs data into a buffer using the format string and argument list.
640 OSStatus
RMxPackVAList( void *inBuffer
, size_t inMaxSize
, size_t *outSize
, const char *inFormat
, va_list inArgs
);
642 //---------------------------------------------------------------------------------------------------------------------------
643 /*! @function RMxUnpack
645 @abstract Unpacks data from a buffer using the format string and arguments.
648 OSStatus
RMxUnpack( const void *inData
, size_t inSize
, const char *inFormat
, ... );
650 //---------------------------------------------------------------------------------------------------------------------------
651 /*! @function RMxUnpackVAList
653 @abstract Unpacks data from a buffer using the format string and argument list.
656 OSStatus
RMxUnpackVAList( const void *inData
, size_t inSize
, const char *inFormat
, va_list inArgs
);
662 #endif // __RMx_COMMON__