1#include <SecureObjectSync/SOSTransport.h>
2#include <SecureObjectSync/SOSTransportMessage.h>
3#include <SecureObjectSync/SOSKVSKeys.h>
4#include <SecureObjectSync/SOSPeerCoder.h>
5#include <SecureObjectSync/SOSEngine.h>
6#include <utilities/SecCFWrappers.h>
7#include <SOSInternal.h>
8#include <SecureObjectSync/SOSAccountPriv.h>
9#include <SOSCloudKeychainClient.h>
10
11CFGiblisWithHashFor(SOSTransportMessage);
12
13SOSTransportMessageRef SOSTransportMessageCreateForSubclass(size_t size,
14                                                                   SOSAccountRef account, CFStringRef circleName,
15                                                                   CFErrorRef *error)
16{
17    SOSTransportMessageRef tpt = CFTypeAllocateWithSpace(SOSTransportMessage, size, kCFAllocatorDefault);
18
19    SOSEngineRef engine = SOSDataSourceFactoryGetEngineForDataSourceName(account->factory, circleName, error);
20
21    tpt->engine = CFRetainSafe(engine);
22    tpt->account = CFRetainSafe(account);
23    return tpt;
24}
25
26
27static CFStringRef SOSTransportMessageCopyDescription(CFTypeRef aObj){
28    SOSTransportMessageRef t = (SOSTransportMessageRef) aObj;
29
30    return t->copyDescription ? t->copyDescription(t)
31                              : CFStringCreateWithFormat(NULL, NULL, CFSTR("<SOSTransportMessage@%p\n>"), t);
32}
33
34static void SOSTransportMessageDestroy(CFTypeRef aObj){
35    SOSTransportMessageRef transport = (SOSTransportMessageRef) aObj;
36
37    if (transport->destroy)
38        transport->destroy(transport);
39
40    CFReleaseSafe(transport->engine);
41}
42
43SOSAccountRef SOSTransportMessageGetAccount(SOSTransportMessageRef transport){
44    return transport->account;
45}
46
47static CFHashCode SOSTransportMessageHash(CFTypeRef obj){
48    return (intptr_t) obj;
49}
50
51static Boolean SOSTransportMessageCompare(CFTypeRef lhs, CFTypeRef rhs){
52    return SOSTransportMessageHash(lhs) == SOSTransportMessageHash(rhs);
53}
54
55bool SOSTransportMessageSendMessages(SOSTransportMessageRef transport, CFDictionaryRef circle_messages, CFErrorRef *error) {
56    return transport->sendMessages(transport, circle_messages, error);
57}
58
59bool SOSTransportMessageFlushChanges(SOSTransportMessageRef transport, CFErrorRef *error){
60    return transport->flushChanges(transport, error);
61}
62
63bool SOSTransportMessageSyncWithPeers(SOSTransportMessageRef transport, CFDictionaryRef circleToPeerIDs, CFErrorRef *error){
64    return transport->syncWithPeers(transport, circleToPeerIDs, error);
65}
66
67bool SOSTransportMessageCleanupAfterPeerMessages(SOSTransportMessageRef transport, CFDictionaryRef circleToPeerIDs, CFErrorRef* error){
68    return transport->cleanupAfterPeerMessages(transport, circleToPeerIDs, error);
69}
70
71CF_RETURNS_RETAINED
72CFDictionaryRef SOSTransportMessageHandleMessages(SOSTransportMessageRef transport, CFMutableDictionaryRef circle_peer_messages_table, CFErrorRef *error){
73    return transport->handleMessages(transport, circle_peer_messages_table, error);
74}
75
76SOSEngineRef SOSTransportMessageGetEngine(SOSTransportMessageRef transport){
77    return transport->engine;
78}
79
80
81bool SOSTransportMessageHandlePeerMessage(SOSTransportMessageRef transport, CFStringRef peer_id, CFDataRef codedMessage, CFErrorRef *error){
82
83    CFDataRef decodedMessage = NULL;
84    bool result = false;
85
86    SOSPeerRef peer = SOSPeerCreateWithEngine(SOSTransportMessageGetEngine(transport), peer_id);
87
88    enum SOSCoderUnwrapStatus uwstatus = SOSPeerHandleCoderMessage(peer, peer_id, codedMessage, &decodedMessage, error);
89
90    if (uwstatus == SOSCoderUnwrapDecoded) {
91        result = SOSEngineHandleMessage(SOSTransportMessageGetEngine(transport), peer_id, decodedMessage, error);
92    } else {
93        result = uwstatus != SOSCoderUnwrapError;
94    }
95    CFReleaseNull(decodedMessage);
96    CFReleaseNull(peer);
97    return result;
98}
99
100bool SOSTransportMessageSendMessageIfNeeded(SOSTransportMessageRef transport, CFStringRef circle_id, CFStringRef peer_id, CFErrorRef *error) {
101
102    SOSEnginePeerMessageSentBlock sent = NULL;
103    CFDataRef message_to_send = NULL;
104    bool ok = false;
105    SOSPeerRef peer = SOSPeerCreateWithEngine(SOSTransportMessageGetEngine(transport), peer_id);
106    CFDataRef coderData = SOSEngineGetCoderData(SOSTransportMessageGetEngine(transport), peer_id);
107    require(coderData, fail);
108
109    SOSCoderRef coder = SOSCoderCreateFromData(coderData, error);
110    require(coder, fail);
111    SOSPeerSetCoder(peer, coder);
112
113    ok = SOSPeerCoderSendMessageIfNeeded(peer, &message_to_send, circle_id, peer_id, &sent, error);
114    coder = SOSPeerGetCoder(peer);
115
116    if (message_to_send)    {
117        CFDictionaryRef peer_dict = CFDictionaryCreateForCFTypes(kCFAllocatorDefault,
118                                                                 peer_id, message_to_send,
119                                                                 NULL);
120        CFDictionaryRef circle_peers = CFDictionaryCreateForCFTypes(kCFAllocatorDefault,
121                                                                    circle_id, peer_dict,
122                                                                    NULL);
123
124        ok = ok && SOSTransportMessageSendMessages(transport, circle_peers, error);
125
126        SOSPeerCoderConsume(&sent, ok);
127
128        CFReleaseSafe(peer_dict);
129        CFReleaseSafe(circle_peers);
130    }
131
132
133    Block_release(sent);
134
135
136    CFReleaseSafe(message_to_send);
137
138    coderData = SOSCoderCopyDER(coder, error);
139
140    if(!SOSEngineSetCoderData(SOSTransportMessageGetEngine(transport), peer_id, coderData, error)){
141        secerror("SOSTransportMessageSendMessageIfNeeded, Could not save peer state");
142    }
143    CFReleaseNull(coderData);
144
145    if (coder)
146        SOSCoderDispose(coder);
147
148fail:
149    CFReleaseNull(peer);
150    return ok;
151}
152
153bool SOSTransportMessageSendMessagesIfNeeded(SOSTransportMessageRef transport, CFStringRef circle_id, CFArrayRef handledPeers, CFErrorRef *error) {
154    CFArrayForEach(handledPeers, ^(const void *value) {
155        if (isString(value)) {
156            CFStringRef peer_id = (CFStringRef) value;
157            CFErrorRef sendError = NULL;
158
159            if (!SOSTransportMessageSendMessageIfNeeded(transport, circle_id, peer_id, &sendError)) {
160                secerror("Error sending message in circle %@ to peer %@ (%@)", circle_id, peer_id, sendError);
161            };
162
163            CFReleaseNull(sendError);
164        }
165    });
166
167    return true;
168}
169
170
171
172
173