1/*
2 * Copyright (c) 2013 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24#include <notify.h>
25#include <stdio.h>
26#include <IOKit/platform/IOPlatformSupportPrivate.h>
27#include "Platform.h"
28#include "PrivateLib.h"
29#include "PMSettings.h"
30
31__private_extern__ CFAbsoluteTime   get_SleepFromUserWakeTime();
32
33__private_extern__ TCPKeepAliveStruct   *gTCPKeepAlive = NULL;
34
35#define kTCPWakeQuotaCountDefault               20
36#define kTCPWakeQuotaIntervalSecDefault         3ULL*60ULL*60ULL
37
38
39
40static void lazyAllocTCPKeepAlive(void)
41{
42    CFDictionaryRef         platformFeatures = NULL;
43    CFNumberRef             expirationTimeout = NULL;
44
45    if (gTCPKeepAlive) {
46        return;
47    }
48
49    platformFeatures = _copyRootDomainProperty(CFSTR("IOPlatformFeatureDefaults"));
50    if (platformFeatures)
51    {
52        gTCPKeepAlive = calloc(1, sizeof(TCPKeepAliveStruct));
53        if (!gTCPKeepAlive) return;
54
55        if (kCFBooleanTrue == CFDictionaryGetValue(platformFeatures,
56                                                   kIOPlatformTCPKeepAliveDuringSleep))
57        {
58            if ((expirationTimeout = CFDictionaryGetValue(platformFeatures,
59                                                          CFSTR("TCPKeepAliveExpirationTimeout"))))
60            {
61                CFNumberGetValue(expirationTimeout, kCFNumberLongType, &gTCPKeepAlive->overrideSec);
62            }
63            gTCPKeepAlive->state = kActive;
64        }
65        else {
66            gTCPKeepAlive->state = kNotSupported;
67        }
68        CFRelease(platformFeatures);
69    }
70
71    return;
72}
73
74__private_extern__ void cancelTCPKeepAliveExpTimer( )
75{
76
77    if (gTCPKeepAlive && gTCPKeepAlive->expiration)
78        dispatch_source_cancel(gTCPKeepAlive->expiration);
79}
80__private_extern__ void startTCPKeepAliveExpTimer( )
81{
82    if ((!gTCPKeepAlive) || (gTCPKeepAlive->state != kActive)) return;
83
84    if (!gTCPKeepAlive->expiration) {
85        gTCPKeepAlive->expiration = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0,
86                                                           0, dispatch_get_main_queue());
87        dispatch_source_set_event_handler(gTCPKeepAlive->expiration, ^{
88                           gTCPKeepAlive->state = kInactive;
89                           configAssertionType(kInteractivePushServiceType, false);
90                           });
91        dispatch_source_set_cancel_handler(gTCPKeepAlive->expiration, ^{
92                           if (gTCPKeepAlive->expiration) {
93                                dispatch_release(gTCPKeepAlive->expiration);
94                                gTCPKeepAlive->expiration = 0;
95                                gTCPKeepAlive->state = kActive;
96                           }
97                           });
98    }
99    else {
100        dispatch_suspend(gTCPKeepAlive->expiration);
101    }
102
103    dispatch_source_set_timer(gTCPKeepAlive->expiration,
104                              dispatch_walltime(NULL, kTCPKeepAliveExpireSecs * NSEC_PER_SEC),
105                              DISPATCH_TIME_FOREVER, 0);
106    dispatch_resume(gTCPKeepAlive->expiration);
107
108}
109
110__private_extern__
111tcpKeepAliveStates_et  getTCPKeepAliveState(char *buf, int buflen)
112{
113    lazyAllocTCPKeepAlive();
114
115    if (!gTCPKeepAlive || (gTCPKeepAlive->state == kNotSupported))
116    {
117        if (buf) snprintf(buf, buflen, "unsupported");
118        return kNotSupported;
119    }
120
121    if (buf) {
122        if (gTCPKeepAlive->state == kActive)
123            snprintf(buf, buflen, "active");
124        else
125            snprintf(buf, buflen, "inactive");
126    }
127    return gTCPKeepAlive->state;
128
129}
130
131
132