+
+/* A timeout callback for the re-key. We will be the initiator of the
+ re-key protocol. */
+
+SILC_TASK_CALLBACK(silc_server_rekey_callback)
+{
+ SilcSocketConnection sock = (SilcSocketConnection)context;
+ SilcIDListData idata = (SilcIDListData)sock->user_data;
+ SilcServer server = (SilcServer)idata->rekey->context;
+ SilcProtocol protocol;
+ SilcServerRekeyInternalContext *proto_ctx;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ /* Allocate internal protocol context. This is sent as context
+ to the protocol. */
+ proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
+ proto_ctx->server = (void *)server;
+ proto_ctx->sock = sock;
+ proto_ctx->responder = FALSE;
+ proto_ctx->pfs = idata->rekey->pfs;
+
+ /* Perform rekey protocol. Will call the final callback after the
+ protocol is over. */
+ silc_protocol_alloc(SILC_PROTOCOL_SERVER_REKEY,
+ &protocol, proto_ctx, silc_server_rekey_final);
+ sock->protocol = protocol;
+
+ /* Run the protocol */
+ silc_protocol_execute(protocol, server->schedule, 0, 0);
+
+ /* Re-register re-key timeout */
+ silc_schedule_task_add(server->schedule, sock->sock,
+ silc_server_rekey_callback,
+ context, idata->rekey->timeout, 0,
+ SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
+}
+
+/* The final callback for the REKEY protocol. This will actually take the
+ new key material into use. */
+
+SILC_TASK_CALLBACK_GLOBAL(silc_server_rekey_final)
+{
+ SilcProtocol protocol = (SilcProtocol)context;
+ SilcServerRekeyInternalContext *ctx =
+ (SilcServerRekeyInternalContext *)protocol->context;
+ SilcServer server = (SilcServer)ctx->server;
+ SilcSocketConnection sock = ctx->sock;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
+ protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
+ /* Error occured during protocol */
+ SILC_LOG_ERROR(("Error occurred during rekey protocol"));
+ silc_protocol_cancel(protocol, server->schedule);
+ silc_protocol_free(protocol);
+ sock->protocol = NULL;
+ if (ctx->packet)
+ silc_packet_context_free(ctx->packet);
+ if (ctx->ske)
+ silc_ske_free(ctx->ske);
+ silc_free(ctx);
+ return;
+ }
+
+ /* Purge the outgoing data queue to assure that all rekey packets really
+ go to the network before we quit the protocol. */
+ silc_server_packet_queue_purge(server, sock);
+
+ /* Cleanup */
+ silc_protocol_free(protocol);
+ sock->protocol = NULL;
+ if (ctx->packet)
+ silc_packet_context_free(ctx->packet);
+ if (ctx->ske)
+ silc_ske_free(ctx->ske);
+ silc_free(ctx);
+}