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 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 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 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 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 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 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