1 /* ccapi/lib/ccapi_context_change_time.c */
2 /*
3 * Copyright 2006, 2007 Massachusetts Institute of Technology.
4 * All Rights Reserved.
5 *
6 * Export of this software from the United States of America may
7 * require a specific license from the United States Government.
8 * It is the responsibility of any person or organization contemplating
9 * export to obtain such a license before exporting.
10 *
11 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
12 * distribute this software and its documentation for any purpose and
13 * without fee is hereby granted, provided that the above copyright
14 * notice appear in all copies and that both that copyright notice and
15 * this permission notice appear in supporting documentation, and that
16 * the name of M.I.T. not be used in advertising or publicity pertaining
17 * to distribution of the software without specific, written prior
18 * permission. Furthermore if you modify this software you must label
19 * your software as modified software and not distribute it in such a
20 * fashion that it might be confused with the original M.I.T. software.
21 * M.I.T. makes no representations about the suitability of
22 * this software for any purpose. It is provided "as is" without express
23 * or implied warranty.
24 */
25
26 #include "ccapi_context_change_time.h"
27 #include "cci_common.h"
28
29 #include "k5-thread.h"
30
31 static cci_identifier_t g_change_time_identifer = NULL;
32 static cc_time_t g_change_time = 0;
33 static cc_time_t g_change_time_offset = 0;
34 static k5_mutex_t g_change_time_mutex = K5_MUTEX_PARTIAL_INITIALIZER;
35
36 /* ------------------------------------------------------------------------ */
37
cci_context_change_time_thread_init(void)38 cc_int32 cci_context_change_time_thread_init (void)
39 {
40 return k5_mutex_finish_init(&g_change_time_mutex);
41 }
42
43 /* ------------------------------------------------------------------------ */
44
cci_context_change_time_thread_fini(void)45 void cci_context_change_time_thread_fini (void)
46 {
47 k5_mutex_destroy(&g_change_time_mutex);
48 }
49
50 /* ------------------------------------------------------------------------ */
51 /* WARNING! Mutex must be locked when calling this! */
52
cci_context_change_time_update_identifier(cci_identifier_t in_new_identifier,cc_uint32 * out_server_ids_match,cc_uint32 * out_old_server_running,cc_uint32 * out_new_server_running)53 static cc_int32 cci_context_change_time_update_identifier (cci_identifier_t in_new_identifier,
54 cc_uint32 *out_server_ids_match,
55 cc_uint32 *out_old_server_running,
56 cc_uint32 *out_new_server_running)
57 {
58 cc_int32 err = ccNoError;
59 cc_uint32 server_ids_match = 0;
60 cc_uint32 old_server_running = 0;
61 cc_uint32 new_server_running = 0;
62
63 if (!in_new_identifier) { err = cci_check_error (err); }
64
65 if (!err && !g_change_time_identifer) {
66 g_change_time_identifer = cci_identifier_uninitialized;
67 }
68
69 if (!err) {
70 err = cci_identifier_compare_server_id (g_change_time_identifer,
71 in_new_identifier,
72 &server_ids_match);
73 }
74
75 if (!err && out_old_server_running) {
76 err = cci_identifier_is_initialized (g_change_time_identifer, &old_server_running);
77 }
78
79 if (!err && out_new_server_running) {
80 err = cci_identifier_is_initialized (in_new_identifier, &new_server_running);
81 }
82
83 if (!err && !server_ids_match) {
84 cci_identifier_t new_change_time_identifer = NULL;
85
86 err = cci_identifier_copy (&new_change_time_identifer, in_new_identifier);
87
88 if (!err) {
89 /* Save the new identifier */
90 if (g_change_time_identifer) {
91 cci_identifier_release (g_change_time_identifer);
92 }
93 g_change_time_identifer = new_change_time_identifer;
94 }
95 }
96
97 if (!err) {
98 if (out_server_ids_match ) { *out_server_ids_match = server_ids_match; }
99 if (out_old_server_running) { *out_old_server_running = old_server_running; }
100 if (out_new_server_running) { *out_new_server_running = new_server_running; }
101 }
102
103
104 return cci_check_error (err);
105 }
106
107 #ifdef TARGET_OS_MAC
108 #pragma mark -
109 #endif
110
111 /* ------------------------------------------------------------------------ */
112
cci_context_change_time_get(cc_time_t * out_change_time)113 cc_int32 cci_context_change_time_get (cc_time_t *out_change_time)
114 {
115 cc_int32 err = ccNoError;
116
117 k5_mutex_lock (&g_change_time_mutex);
118
119 *out_change_time = g_change_time + g_change_time_offset;
120 k5_mutex_unlock (&g_change_time_mutex);
121
122 return err;
123 }
124
125 /* ------------------------------------------------------------------------ */
126
cci_context_change_time_update(cci_identifier_t in_identifier,cc_time_t in_new_change_time)127 cc_int32 cci_context_change_time_update (cci_identifier_t in_identifier,
128 cc_time_t in_new_change_time)
129 {
130 cc_int32 err = ccNoError;
131 k5_mutex_lock (&g_change_time_mutex);
132
133 if (!in_identifier) { err = cci_check_error (err); }
134
135 if (!err) {
136 if (g_change_time < in_new_change_time) {
137 /* Only update if it increases the time. May be a different server. */
138 g_change_time = in_new_change_time;
139 cci_debug_printf ("%s: setting change time to %d",
140 __FUNCTION__, in_new_change_time);
141 }
142 }
143
144 if (!err) {
145 err = cci_context_change_time_update_identifier (in_identifier,
146 NULL, NULL, NULL);
147 }
148
149 k5_mutex_unlock (&g_change_time_mutex);
150
151 return err;
152 }
153
154 /* ------------------------------------------------------------------------ */
155
cci_context_change_time_sync(cci_identifier_t in_new_identifier)156 cc_int32 cci_context_change_time_sync (cci_identifier_t in_new_identifier)
157 {
158 cc_int32 err = ccNoError;
159 cc_uint32 server_ids_match = 0;
160 cc_uint32 server_was_running = 0;
161 cc_uint32 server_is_running = 0;
162
163 k5_mutex_lock (&g_change_time_mutex);
164
165 if (!in_new_identifier) { err = cci_check_error (err); }
166
167 if (!err) {
168 err = cci_context_change_time_update_identifier (in_new_identifier,
169 &server_ids_match,
170 &server_was_running,
171 &server_is_running);
172 }
173
174 if (!err && !server_ids_match) {
175 /* Increment the change time so callers re-read */
176 g_change_time_offset++;
177
178 /* If the server died, absorb the offset */
179 if (server_was_running && !server_is_running) {
180 cc_time_t now = time (NULL);
181
182 g_change_time += g_change_time_offset;
183 g_change_time_offset = 0;
184
185 /* Make sure the change time increases, ideally with the current time */
186 g_change_time = (g_change_time < now) ? now : g_change_time;
187 }
188
189 cci_debug_printf ("%s noticed server changed ("
190 "server_was_running = %d; server_is_running = %d; "
191 "g_change_time = %d; g_change_time_offset = %d",
192 __FUNCTION__, server_was_running, server_is_running,
193 g_change_time, g_change_time_offset);
194 }
195
196 k5_mutex_unlock (&g_change_time_mutex);
197
198 return err;
199 }
200