1
2#include <SecureObjectSync/SOSPeer.h>
3#include <SecureObjectSync/SOSTransportCoder.h>
4#include <SecureObjectSync/SOSTransportMessage.h>
5#include <SecureObjectSync/SOSCoder.h>
6#include <SecureObjectSync/SOSAccount.h>
7#include <SecureObjectSync/SOSAccountPriv.h>
8#include <SecureObjectSync/SOSEngine.h>
9
10#include <utilities/debugging.h>
11#include <utilities/SecCFWrappers.h>
12
13#include <AssertMacros.h>
14#include <SOSInternal.h>
15
16
17// For now transport (the abstract class) consumes the Transport data in engine to hold
18// coder state.
19static SOSCoderRef SOSTransportMessageCopyPeerCoder(SOSTransportMessageRef transport, CFStringRef peer_id){
20    SOSCoderRef coder = NULL;
21
22    CFDataRef coderData = SOSEngineGetTransportData(SOSTransportMessageGetEngine(transport), peer_id);
23
24    if (coderData) {
25        CFErrorRef localError = NULL;
26        coder = SOSCoderCreateFromData(coderData, &localError);
27
28        if (!coder) {
29            secerror("Failed to make coder from valid data for peer %@ (%@). THIS IS FATAL, WE CAN'T COMMUNICATE.", peer_id, localError);
30        }
31
32        CFReleaseNull(localError);
33    }
34    else
35        secerror("Failed to get coderData from engine for peer %@. THIS IS FATAL, WE CAN'T COMMUNICATE.", peer_id);
36
37    return coder;
38}
39
40bool SOSTransportMessageSavePeerCoderData(SOSTransportMessageRef transport, SOSCoderRef coder, CFStringRef peer_id, CFErrorRef *error) {
41    CFDataRef coderData = NULL;
42    bool ok = true;
43
44    if (coder) {
45        coderData = SOSCoderCopyDER(coder, error);
46        if (coderData == NULL) {
47            secerror("%@ coder data failed to export %@, zapping data", transport, error ? *error : 0);
48        }
49    }
50    require_action_quiet(coderData, exit, ok = SOSErrorCreate(kSOSErrorAllocationFailure, error, NULL, CFSTR("Creation of coder data failed")));
51
52    ok = SOSEngineSetTransportData(SOSTransportMessageGetEngine(transport), peer_id, coderData, error);
53
54exit:
55    CFReleaseNull(coderData);
56    return ok;
57}
58
59bool SOSTransportCoderInitializeForPeer(SOSTransportMessageRef transport, SOSFullPeerInfoRef myPeerInfo, SOSPeerInfoRef peerInfo, CFErrorRef *error){
60    SOSCoderRef coder = NULL;
61    CFStringRef peer_id = SOSPeerInfoGetPeerID(peerInfo);
62    CFDataRef coderData = SOSEngineGetTransportData(SOSTransportMessageGetEngine(transport), peer_id);
63    if(coderData != NULL) {
64        CFErrorRef coderError = NULL;
65        coder = SOSCoderCreateFromData(coderData, &coderError);
66
67        if (!coder) {
68            secerror("Found data but couldn't make coder for %@: %@", peer_id, coderError);
69        }
70        CFReleaseNull(coderError);
71    }
72
73    bool haveGoodCoder = coder;
74    if (!haveGoodCoder) {
75        secnotice("transport", "New coder for id %@.", peer_id);
76        coder = SOSCoderCreate(peerInfo, myPeerInfo, error);
77
78        if (coder) {
79            haveGoodCoder = SOSTransportMessageSavePeerCoderData(transport, coder, peer_id, error);
80        } else {
81            secerror("Couldn't make coder for %@", peer_id);
82        }
83    }
84
85    if (coder)
86        SOSCoderDispose(coder);
87    return haveGoodCoder;
88}
89
90enum SOSCoderUnwrapStatus SOSTransportMessageHandleCoderMessage(SOSTransportMessageRef transport, CFStringRef peer_id, CFDataRef codedMessage, CFDataRef *decodedMessage, CFErrorRef *error){
91
92    enum SOSCoderUnwrapStatus result = SOSCoderUnwrapError;
93    CFMutableDataRef localDecodedMessage = NULL;
94
95    SOSCoderStatus coderStatus = kSOSCoderDataReturned;
96    SOSCoderRef coder = SOSTransportMessageCopyPeerCoder(transport, peer_id);
97    if(!coder){
98        SOSAccountEnsurePeerRegistration(SOSTransportMessageGetAccount(transport), error);
99        coder = SOSTransportMessageCopyPeerCoder(transport, peer_id);
100        secnotice("transport", "Building new coder!");
101    }
102    CFErrorRef localError = NULL;
103    if (coder) {
104        coderStatus = SOSCoderUnwrap(coder, codedMessage, &localDecodedMessage, peer_id, error);
105
106        switch(coderStatus) {
107            case kSOSCoderDataReturned: {
108                logRawMessage(localDecodedMessage, false, 0);
109                result = SOSCoderUnwrapDecoded;
110                break;
111            }
112            case kSOSCoderNegotiating:  // Sent message already in Unwrap.
113                result = SOSCoderUnwrapHandled;
114                secnotice("transport", "%@ transport negotiating", peer_id);
115                break;
116            case kSOSCoderNegotiationCompleted:
117                if(SOSEnginePeerDidConnect(SOSTransportMessageGetEngine(transport), peer_id, error))
118                    result = SOSCoderUnwrapHandled;
119                secnotice("transport", "%@ transport negotiation complete", peer_id);
120                break;
121            case kSOSCoderFailure:      // Probably restart coder
122                secnotice("transport", "%@ transport failed handling message %@", peer_id, error ? *error : NULL);
123                SOSCoderReset(coder);
124                if(SOSCoderStart(coder, &localError) == kSOSCoderFailure){
125                    secerror("Attempt to recover coder failed to restart: %@", localError);
126                }
127                break;
128            case kSOSCoderStaleEvent:   // We received an event we have already processed in the past.
129                secnotice("transport", "%@ transport stale event ignored", peer_id);
130                break;
131            default:
132                assert(false);
133                break;
134        }
135        if(decodedMessage)
136            *decodedMessage = CFRetainSafe(localDecodedMessage);
137        CFReleaseNull(localDecodedMessage);
138
139        SOSTransportMessageSavePeerCoderData(transport, coder, peer_id, NULL);
140        SOSCoderDispose(coder);
141    }
142    else{
143        secerror("SOSTransportMessageHandleCoderMessage: Could not make a new coder!");
144    }
145
146    CFReleaseNull(localError);
147
148    return result;
149
150}
151
152#warning this should be SOSTransportMessage and be split up into coder/message pieces
153/* Send a message to peer if needed.  Return false if there was an error, true otherwise. */
154bool SOSTransportMessageSendMessageIfNeeded(SOSTransportMessageRef transport, CFStringRef circle_id, CFStringRef peer_id, CFErrorRef *error) {
155    SOSCoderRef coder = SOSTransportMessageCopyPeerCoder(transport, peer_id);
156
157    if(!coder){
158        SOSAccountEnsurePeerRegistration(SOSTransportMessageGetAccount(transport), error);
159        coder = SOSTransportMessageCopyPeerCoder(transport, peer_id);
160    }
161    CFDataRef message_to_send = NULL;
162    bool ok = false;
163    SOSEnginePeerMessageSentBlock sent = NULL;
164
165    require_action_quiet(coder, fail, SOSCreateError(kSOSErrorAllocationFailure, CFSTR("SOSTransportMessageCopyPeerCoder failed"), *error, error));
166
167    if (SOSCoderCanWrap(coder)) {
168        secnotice("transport", "%@ Coder can wrap, getting message from engine", peer_id);
169        CFMutableDataRef codedMessage = NULL;
170        CFDataRef message = SOSEngineCreateMessageToSyncToPeer(SOSTransportMessageGetEngine(transport), peer_id, &sent, error);
171        if (!message) {
172            secnotice("transport", "%@ SOSEngineCreateMessageToSyncToPeer failed: %@",peer_id, *error);
173        }
174        ok = message && (SOSCoderWrap(coder, message, &codedMessage, peer_id, error) == kSOSCoderDataReturned);
175        if (!ok) {
176            secnotice("transport", "%@ SOSCoderWrap failed: %@",peer_id, *error);
177        }
178
179        if (ok)
180            CFRetainAssign(message_to_send, codedMessage);
181
182        CFReleaseNull(codedMessage);
183        CFReleaseNull(message);
184    } else {
185        message_to_send = SOSCoderCopyPendingResponse(coder);
186        secnotice("transport", "%@ Negotiating, %@", peer_id, message_to_send ? CFSTR("Sending negotiation message.") : CFSTR("waiting for negotiation message."));
187        sent = Block_copy(^(bool wasSent){
188            if (wasSent)
189                SOSCoderConsumeResponse(coder);
190        });
191        ok = true;
192    }
193
194    if (message_to_send)    {
195        CFDictionaryRef peer_dict = CFDictionaryCreateForCFTypes(kCFAllocatorDefault,
196                                                                 peer_id, message_to_send,
197                                                                 NULL);
198        CFDictionaryRef circle_peers = CFDictionaryCreateForCFTypes(kCFAllocatorDefault,
199                                                                    circle_id, peer_dict,
200                                                                    NULL);
201
202        ok = ok && SOSTransportMessageSendMessages(transport, circle_peers, error);
203
204        if (sent)
205            sent(ok);
206
207        CFReleaseSafe(peer_dict);
208        CFReleaseSafe(circle_peers);
209    }
210
211    Block_release(sent);
212
213    CFReleaseSafe(message_to_send);
214
215    SOSTransportMessageSavePeerCoderData(transport, coder, peer_id, NULL);
216
217fail:
218    if (coder)
219        SOSCoderDispose(coder);
220    return ok;
221}
222