/src/plugins/sched/wiki/msg.c
C | 739 lines | 561 code | 74 blank | 104 comment | 127 complexity | cc188aa67a4a9fa90905d837a3ef3a45 MD5 | raw file
Possible License(s): GPL-2.0, AGPL-1.0
- /*****************************************************************************\
- * msg.c - Message/communcation manager for Wiki plugin
- *****************************************************************************
- * Copyright (C) 2006-2007 The Regents of the University of California.
- * Copyright (C) 2008-2009 Lawrence Livermore National Security.
- * Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
- * Written by Morris Jette <jette1@llnl.gov>
- * CODE-OCEC-09-009. All rights reserved.
- *
- * This file is part of SLURM, a resource management program.
- * For details, see <http://www.schedmd.com/slurmdocs/>.
- * Please also read the included file: DISCLAIMER.
- *
- * SLURM is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
- *
- * In addition, as a special exception, the copyright holders give permission
- * to link the code of portions of this program with the OpenSSL library under
- * certain conditions as described in each individual source file, and
- * distribute linked combinations including the two. You must obey the GNU
- * General Public License in all respects for all of the code used other than
- * OpenSSL. If you modify file(s) with this exception, you may extend this
- * exception to your version of the file(s), but you are not obligated to do
- * so. If you do not wish to do so, delete this exception statement from your
- * version. If you delete this exception statement from all source files in
- * the program, then also delete it here.
- *
- * SLURM is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- * details.
- *
- * You should have received a copy of the GNU General Public License along
- * with SLURM; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- \*****************************************************************************/
- #include "slurm/slurm.h"
- #include "src/common/uid.h"
- #include "src/slurmctld/locks.h"
- #include "src/plugins/sched/wiki/crypto.h"
- #include "src/plugins/sched/wiki/msg.h"
- #define _DEBUG 0
- static bool thread_running = false;
- static bool thread_shutdown = false;
- static pthread_mutex_t thread_flag_mutex = PTHREAD_MUTEX_INITIALIZER;
- static pthread_t msg_thread_id;
- static char *err_msg;
- static int err_code;
- static uint16_t sched_port;
- /* Global configuration parameters */
- char auth_key[KEY_SIZE] = "";
- char e_host[E_HOST_SIZE] = "";
- char e_host_bu[E_HOST_SIZE] = "";
- uint16_t e_port = 0;
- struct part_record *exclude_part_ptr[EXC_PART_CNT];
- struct part_record *hide_part_ptr[HIDE_PART_CNT];
- struct part_record *hide_part_nodes_ptr[HIDE_PART_CNT];
- uint16_t job_aggregation_time = 10; /* Default value is 10 seconds */
- uint16_t host_format;
- int init_prio_mode = PRIO_HOLD;
- uint16_t kill_wait;
- uint16_t use_host_exp = 0;
- static char * _get_wiki_conf_path(void);
- static void * _msg_thread(void *no_data);
- static int _parse_msg(char *msg, char **req);
- static void _proc_msg(slurm_fd_t new_fd, char *msg);
- static size_t _read_bytes(int fd, char *buf, const size_t size);
- static char * _recv_msg(slurm_fd_t new_fd);
- static size_t _send_msg(slurm_fd_t new_fd, char *buf, size_t size);
- static void _send_reply(slurm_fd_t new_fd, char *response);
- static size_t _write_bytes(int fd, char *buf, const size_t size);
- /*****************************************************************************\
- * spawn message hander thread
- \*****************************************************************************/
- extern int spawn_msg_thread(void)
- {
- pthread_attr_t thread_attr_msg;
- pthread_mutex_lock( &thread_flag_mutex );
- if (thread_running) {
- error("Wiki thread already running, not starting another");
- pthread_mutex_unlock(&thread_flag_mutex);
- return SLURM_ERROR;
- }
- parse_wiki_config();
- slurm_attr_init(&thread_attr_msg);
- if (pthread_create(&msg_thread_id, &thread_attr_msg,
- _msg_thread, NULL))
- fatal("pthread_create %m");
- slurm_attr_destroy(&thread_attr_msg);
- thread_running = true;
- pthread_mutex_unlock(&thread_flag_mutex);
- return SLURM_SUCCESS;
- }
- /*****************************************************************************\
- * terminate message hander thread
- \*****************************************************************************/
- extern void term_msg_thread(void)
- {
- pthread_mutex_lock(&thread_flag_mutex);
- if (thread_running) {
- int fd;
- slurm_addr_t addr;
- thread_shutdown = true;
- /* Open and close a connection to the wiki listening port.
- * Allows slurm_accept_msg_conn() to return in
- * _msg_thread() so that it can check the thread_shutdown
- * flag.
- */
- slurm_set_addr(&addr, sched_port, "localhost");
- fd = slurm_open_stream(&addr);
- if (fd != -1) {
- /* we don't care if the open failed */
- slurm_close_stream(fd);
- }
- debug2("waiting for sched/wiki thread to exit");
- pthread_join(msg_thread_id, NULL);
- msg_thread_id = 0;
- thread_shutdown = false;
- thread_running = false;
- debug2("join of sched/wiki thread was successful");
- }
- pthread_mutex_unlock(&thread_flag_mutex);
- }
- /*****************************************************************************\
- * message hander thread
- \*****************************************************************************/
- static void *_msg_thread(void *no_data)
- {
- slurm_fd_t sock_fd = -1, new_fd;
- slurm_addr_t cli_addr;
- char *msg;
- slurm_ctl_conf_t *conf;
- int i;
- /* Locks: Write configuration, job, node, and partition */
- slurmctld_lock_t config_write_lock = {
- WRITE_LOCK, WRITE_LOCK, WRITE_LOCK, WRITE_LOCK };
- conf = slurm_conf_lock();
- sched_port = conf->schedport;
- slurm_conf_unlock();
- /* Wait until configuration is completely loaded */
- lock_slurmctld(config_write_lock);
- unlock_slurmctld(config_write_lock);
- /* If SchedulerPort is already taken, keep trying to open it
- * once per minute. Slurmctld will continue to function
- * during this interval even if nothing can be scheduled. */
- for (i=0; (!thread_shutdown); i++) {
- if (i > 0)
- sleep(60);
- sock_fd = slurm_init_msg_engine_port(sched_port);
- if (sock_fd != SLURM_SOCKET_ERROR)
- break;
- error("wiki: slurm_init_msg_engine_port %u %m",
- sched_port);
- error("wiki: Unable to communicate with Moab");
- }
- /* Process incoming RPCs until told to shutdown */
- while (!thread_shutdown) {
- if ((new_fd = slurm_accept_msg_conn(sock_fd, &cli_addr))
- == SLURM_SOCKET_ERROR) {
- if (errno != EINTR)
- error("wiki: slurm_accept_msg_conn %m");
- continue;
- }
- if (thread_shutdown) {
- close(new_fd);
- break;
- }
- /* It would be nice to create a pthread for each new
- * RPC, but that leaks memory on some systems when
- * done from a plugin.
- * FIXME: Maintain a pool of and reuse them. */
- err_code = 0;
- err_msg = "";
- msg = _recv_msg(new_fd);
- if (msg) {
- _proc_msg(new_fd, msg);
- xfree(msg);
- }
- slurm_close_accepted_conn(new_fd);
- }
- if (sock_fd > 0)
- (void) slurm_shutdown_msg_engine(sock_fd);
- pthread_exit((void *) 0);
- return NULL;
- }
- /*****************************************************************************\
- * _get_wiki_conf_path - return the pathname of the wiki.conf file
- * return value must be xfreed
- \*****************************************************************************/
- static char * _get_wiki_conf_path(void)
- {
- char *val = getenv("SLURM_CONF");
- char *path = NULL;
- int i;
- if (!val)
- val = default_slurm_config_file;
- /* Replace file name on end of path */
- i = strlen(val) + 10;
- path = xmalloc(i);
- strcpy(path, val);
- val = strrchr(path, (int)'/');
- if (val) /* absolute path */
- val++;
- else /* not absolute path */
- val = path;
- strcpy(val, "wiki.conf");
- return path;
- }
- /*****************************************************************************\
- * parse_wiki_config - Results go into global variables
- * RET SLURM_SUCESS or error code
- *
- * wiki_conf options
- * JobPriority=hold|run
- * AuthKey=number
- \*****************************************************************************/
- extern int parse_wiki_config(void)
- {
- s_p_options_t options[] = {
- {"AuthKey", S_P_STRING},
- {"EHost", S_P_STRING},
- {"EHostBackup", S_P_STRING},
- {"EPort", S_P_UINT16},
- {"ExcludePartitions", S_P_STRING},
- {"HidePartitionJobs", S_P_STRING},
- {"HidePartitionNodes", S_P_STRING},
- {"HostFormat", S_P_UINT16},
- {"JobAggregationTime", S_P_UINT16},
- {"JobPriority", S_P_STRING},
- {NULL} };
- s_p_hashtbl_t *tbl;
- char *exclude_partitions, *hide_partitions, *hide_part_nodes;
- char *key = NULL, *priority_mode = NULL, *wiki_conf;
- struct stat buf;
- slurm_ctl_conf_t *conf;
- int i;
- /* Set default values */
- for (i=0; i<EXC_PART_CNT; i++)
- exclude_part_ptr[i] = NULL;
- for (i=0; i<HIDE_PART_CNT; i++)
- hide_part_ptr[i] = NULL;
- for (i=0; i<HIDE_PART_CNT; i++)
- hide_part_nodes_ptr[i] = NULL;
- conf = slurm_conf_lock();
- strncpy(e_host, conf->control_addr, sizeof(e_host));
- if (conf->backup_addr) {
- strncpy(e_host_bu, conf->backup_addr,
- sizeof(e_host));
- }
- kill_wait = conf->kill_wait;
- slurm_conf_unlock();
- wiki_conf = _get_wiki_conf_path();
- if ((wiki_conf == NULL) || (stat(wiki_conf, &buf) == -1)) {
- debug("No wiki.conf file (%s)", wiki_conf);
- xfree(wiki_conf);
- return SLURM_SUCCESS;
- }
- debug("Reading wiki.conf file (%s)",wiki_conf);
- tbl = s_p_hashtbl_create(options);
- if (s_p_parse_file(tbl, NULL, wiki_conf, false) == SLURM_ERROR)
- fatal("something wrong with opening/reading wiki.conf file");
- if (! s_p_get_string(&key, "AuthKey", tbl))
- debug("Warning: No wiki_conf AuthKey specified");
- else {
- strncpy(auth_key, key, sizeof(auth_key));
- xfree(key);
- }
- if ( s_p_get_string(&key, "EHost", tbl)) {
- strncpy(e_host, key, sizeof(e_host));
- xfree(key);
- } else
- debug("wiki: Using ControlAddr for EHost value");
- if ( s_p_get_string(&key, "EHostBackup", tbl)) {
- strncpy(e_host_bu, key, sizeof(e_host_bu));
- xfree(key);
- }
- s_p_get_uint16(&e_port, "EPort", tbl);
- if (s_p_get_uint16(&job_aggregation_time, "JobAggregationTime", tbl))
- error("JobAggregationTime not used by sched/wiki");
- if (s_p_get_uint16(&host_format, "HostFormat", tbl))
- error("HostFormat not used by sched/wiki");
- if (s_p_get_string(&exclude_partitions, "ExcludePartitions", tbl)) {
- char *tok = NULL, *tok_p = NULL;
- tok = strtok_r(exclude_partitions, ",", &tok_p);
- i = 0;
- while (tok) {
- if (i >= EXC_PART_CNT) {
- error("ExcludePartitions has too many entries "
- "skipping %s and later entries", tok);
- break;
- }
- exclude_part_ptr[i] = find_part_record(tok);
- if (exclude_part_ptr[i])
- i++;
- else
- error("ExcludePartitions %s not found", tok);
- tok = strtok_r(NULL, ",", &tok_p);
- }
- }
- if (s_p_get_string(&hide_partitions, "HidePartitionJobs", tbl)) {
- char *tok = NULL, *tok_p = NULL;
- tok = strtok_r(hide_partitions, ",", &tok_p);
- i = 0;
- while (tok) {
- if (i >= HIDE_PART_CNT) {
- error("HidePartitionJobs has too many entries "
- "skipping %s and later entries", tok);
- break;
- }
- hide_part_ptr[i] = find_part_record(tok);
- if (hide_part_ptr[i])
- i++;
- else
- error("HidePartitionJobs %s not found", tok);
- tok = strtok_r(NULL, ",", &tok_p);
- }
- }
- if (s_p_get_string(&hide_part_nodes, "HidePartitionNodes", tbl)) {
- char *tok = NULL, *tok_p = NULL;
- tok = strtok_r(hide_part_nodes, ",", &tok_p);
- i = 0;
- while (tok) {
- if (i >= HIDE_PART_CNT) {
- error("HidePartitionNodes has too many entries "
- "skipping %s and later entries", tok);
- break;
- }
- hide_part_nodes_ptr[i] = find_part_record(tok);
- if (hide_part_nodes_ptr[i])
- i++;
- else
- error("HidePartitionNodes %s not found", tok);
- tok = strtok_r(NULL, ",", &tok_p);
- }
- }
- if (s_p_get_string(&priority_mode, "JobPriority", tbl)) {
- if (strcasecmp(priority_mode, "hold") == 0)
- init_prio_mode = PRIO_HOLD;
- else if (strcasecmp(priority_mode, "run") == 0)
- init_prio_mode = PRIO_DECREMENT;
- else
- error("Invalid value for JobPriority in wiki.conf");
- xfree(priority_mode);
- }
- s_p_hashtbl_destroy(tbl);
- xfree(wiki_conf);
- #if _DEBUG
- info("AuthKey = %s", auth_key);
- info("EHost = %s", e_host);
- info("EHostBackup = %s", e_host_bu);
- info("EPort = %u", e_port);
- info("JobAggregationTime = %u sec", job_aggregation_time);
- info("JobPriority = %s", init_prio_mode ? "run" : "hold");
- info("KillWait = %u sec", kill_wait);
- for (i=0; i<EXC_PART_CNT; i++) {
- if (!exclude_part_ptr[i])
- continue;
- info("ExcludePartitions = %s", exclude_part_ptr[i]->name);
- }
- for (i=0; i<HIDE_PART_CNT; i++) {
- if (!hide_part_ptr[i])
- continue;
- info("HidePartitionJobs = %s", hide_part_ptr[i]->name);
- }
- for (i=0; i<HIDE_PART_CNT; i++) {
- if (!hide_part_nodes_ptr[i])
- continue;
- info("HidePartitionNodes = %s", hide_part_nodes_ptr[i]->name);
- }
- #endif
- return SLURM_SUCCESS;
- }
- extern char * get_wiki_conf(void)
- {
- int i, first;
- char buf[32], *conf = NULL;
- snprintf(buf, sizeof(buf), "HostFormat=%u", use_host_exp);
- xstrcat(conf, buf);
- snprintf(buf, sizeof(buf), ";JobAggregationTime=%u",
- job_aggregation_time);
- xstrcat(conf, buf);
- first = 1;
- for (i=0; i<EXC_PART_CNT; i++) {
- if (!exclude_part_ptr[i])
- continue;
- if (first) {
- xstrcat(conf, ";ExcludePartitions=");
- first = 0;
- } else
- xstrcat(conf, ",");
- xstrcat(conf, exclude_part_ptr[i]->name);
- }
- first = 1;
- for (i=0; i<HIDE_PART_CNT; i++) {
- if (!hide_part_ptr[i])
- continue;
- if (first) {
- xstrcat(conf, ";HidePartitionJobs=");
- first = 0;
- } else
- xstrcat(conf, ",");
- xstrcat(conf, hide_part_ptr[i]->name);
- }
- first = 1;
- for (i=0; i<HIDE_PART_CNT; i++) {
- if (!hide_part_nodes_ptr[i])
- continue;
- if (first) {
- xstrcat(conf, ";HidePartitionNodes=");
- first = 0;
- } else
- xstrcat(conf, ",");
- xstrcat(conf, hide_part_nodes_ptr[i]->name);
- }
- return conf;
- }
- static size_t _read_bytes(int fd, char *buf, const size_t size)
- {
- size_t bytes_remaining, bytes_read;
- char *ptr;
- bytes_remaining = size;
- ptr = buf;
- while (bytes_remaining > 0) {
- bytes_read = read(fd, ptr, bytes_remaining);
- if (bytes_read <= 0)
- return 0;
- bytes_remaining -= bytes_read;
- ptr += bytes_read;
- }
- return size;
- }
- static size_t _write_bytes(int fd, char *buf, const size_t size)
- {
- size_t bytes_remaining, bytes_written;
- char *ptr;
- bytes_remaining = size;
- ptr = buf;
- while (bytes_remaining > 0) {
- bytes_written = write(fd, ptr, bytes_remaining);
- if (bytes_written <= 0)
- return (size - bytes_remaining);
- bytes_remaining -= bytes_written;
- ptr += bytes_written;
- }
- return size;
- }
- /*****************************************************************************\
- * Read a message (request) from specified file descriptor
- *
- * RET - The message which must be xfreed or
- * NULL on error
- \*****************************************************************************/
- static char * _recv_msg(slurm_fd_t new_fd)
- {
- char header[10];
- unsigned long size;
- char *buf;
- if (_read_bytes((int) new_fd, header, 9) != 9) {
- err_code = -240;
- err_msg = "failed to read message header";
- error("wiki: failed to read message header %m");
- return NULL;
- }
- if (sscanf(header, "%lu", &size) != 1) {
- err_code = -244;
- err_msg = "malformed message header";
- error("wiki: malformed message header (%s)", header);
- return NULL;
- }
- buf = xmalloc(size + 1); /* need '\0' on end to print */
- if (_read_bytes((int) new_fd, buf, size) != size) {
- err_code = -246;
- err_msg = "unable to read all message data";
- error("wiki: unable to read data message");
- xfree(buf);
- return NULL;
- }
- if (slurm_get_debug_flags() & DEBUG_FLAG_WIKI)
- info("wiki msg recv:%s", buf);
- return buf;
- }
- /*****************************************************************************\
- * Send a message (response) to specified file descriptor
- *
- * RET - Number of data bytes written (excludes header)
- \*****************************************************************************/
- static size_t _send_msg(slurm_fd_t new_fd, char *buf, size_t size)
- {
- char header[10];
- size_t data_sent;
- if (slurm_get_debug_flags() & DEBUG_FLAG_WIKI)
- info("wiki msg send:%s", buf);
- (void) sprintf(header, "%08lu\n", (unsigned long) size);
- if (_write_bytes((int) new_fd, header, 9) != 9) {
- error("wiki: failed to write message header %m");
- return 0;
- }
- data_sent = _write_bytes((int) new_fd, buf, size);
- if (data_sent != size) {
- error("wiki: unable to write data message (%lu of %lu) %m",
- (long unsigned) data_sent, (long unsigned) size);
- }
- return data_sent;
- }
- /*****************************************************************************\
- * Parse and checksum a wiki request
- * msg IN - message to parse
- * req OUT - pointer the request portion of the message
- * RET 0 on success, -1 on error
- \*****************************************************************************/
- static int _parse_msg(char *msg, char **req)
- {
- char *auth_ptr = strstr(msg, "AUTH=");
- char *dt_ptr = strstr(msg, "DT=");
- char *ts_ptr = strstr(msg, "TS=");
- char *cmd_ptr = strstr(msg, "CMD=");
- time_t ts, now = time(NULL);
- uint32_t delta_t;
- if ((auth_key[0] == '\0') && cmd_ptr) {
- /* No authentication required */
- *req = cmd_ptr;
- return 0;
- }
- if (!auth_ptr) {
- err_code = -300;
- err_msg = "request lacks AUTH";
- error("wiki: request lacks AUTH=");
- return -1;
- }
- if (!dt_ptr) {
- err_code = -300;
- err_msg = "request lacks DT";
- error("wiki: request lacks DT=");
- return -1;
- }
- if (!ts_ptr) {
- err_code = -300;
- err_msg = "request lacks TS";
- error("wiki: request lacks TS=");
- return -1;
- }
- ts = strtoul((ts_ptr+3), NULL, 10);
- if (ts < now)
- delta_t = (uint32_t) difftime(now, ts);
- else
- delta_t = (uint32_t) difftime(ts, now);
- if (delta_t > 300) {
- err_code = -350;
- err_msg = "TS value too far from NOW";
- error("wiki: TimeStamp too far from NOW (%u secs)",
- delta_t);
- return -1;
- }
- #if 0
- /* Old wiki interface does not require checksum
- * (actually a cryptographic signature) on incoming
- * messages. NOTE: This is not secure! */
- if (auth_key[0] != '\0') {
- char sum[20]; /* format is "CK=%08x08x" */
- checksum(sum, auth_key, ts_ptr);
- if (strncmp(sum, msg, 19) != 0) {
- err_code = -422;
- err_msg = "bad checksum";
- error("wiki: message checksum error, "
- "check AuthKey in wiki.conf");
- return -1;
- }
- }
- #endif
- *req = dt_ptr + 3;
- return 0;
- }
- /*****************************************************************************\
- * Parse, process and respond to a request
- \*****************************************************************************/
- static void _proc_msg(slurm_fd_t new_fd, char *msg)
- {
- DEF_TIMERS;
- char *req, *cmd_ptr, *msg_type = NULL;
- char response[128];
- if (new_fd < 0)
- return;
- START_TIMER;
- if (!msg) {
- err_code = -300;
- err_msg = "NULL request message";
- error("wiki: NULL request message");
- goto resp_msg;
- }
- if (_parse_msg(msg, &req) != 0)
- goto resp_msg;
- cmd_ptr = strstr(req, "CMD=");
- if (cmd_ptr == NULL) {
- err_code = -300;
- err_msg = "request lacks CMD";
- error("wiki: request lacks CMD");
- goto resp_msg;
- }
- cmd_ptr +=4;
- err_code = 0;
- if (strncmp(cmd_ptr, "GETJOBS", 7) == 0) {
- msg_type = "wiki:GETJOBS";
- if (!get_jobs(cmd_ptr, &err_code, &err_msg))
- goto free_resp_msg;
- } else if (strncmp(cmd_ptr, "GETNODES", 8) == 0) {
- msg_type = "wiki:GETNODES";
- if (!get_nodes(cmd_ptr, &err_code, &err_msg))
- goto free_resp_msg;
- } else if (strncmp(cmd_ptr, "STARTJOB", 8) == 0) {
- msg_type = "wiki:STARTJOB";
- start_job(cmd_ptr, &err_code, &err_msg);
- } else if (strncmp(cmd_ptr, "CANCELJOB", 9) == 0) {
- msg_type = "wiki:CANCELJOB";
- cancel_job(cmd_ptr, &err_code, &err_msg);
- } else if (strncmp(cmd_ptr, "SUSPENDJOB", 10) == 0) {
- msg_type = "wiki:SUSPENDJOB";
- suspend_job(cmd_ptr, &err_code, &err_msg);
- } else if (strncmp(cmd_ptr, "RESUMEJOB", 9) == 0) {
- msg_type = "wiki:RESUMEJOB";
- resume_job(cmd_ptr, &err_code, &err_msg);
- } else if (strncmp(cmd_ptr, "MODIFYJOB", 9) == 0) {
- msg_type = "wiki:MODIFYJOB";
- job_modify_wiki(cmd_ptr, &err_code, &err_msg);
- } else {
- err_code = -300;
- err_msg = "unsupported request type";
- error("wiki: unrecognized request type: %s", req);
- }
- END_TIMER2(msg_type);
- resp_msg:
- snprintf(response, sizeof(response),
- "SC=%d RESPONSE=%s", err_code, err_msg);
- _send_reply(new_fd, response);
- return;
- free_resp_msg:
- /* Message is pre-formatted by get_jobs and get_nodes
- * ONLY if no error. Send message and xfree the buffer. */
- _send_reply(new_fd, err_msg);
- xfree(err_msg);
- return;
- }
- static void _send_reply(slurm_fd_t new_fd, char *response)
- {
- size_t i;
- char *buf, sum[20], *tmp;
- static char uname[64] = "";
- i = strlen(response);
- i += 100; /* leave room for header */
- buf = xmalloc(i);
- if (uname[0] == '\0') {
- tmp = uid_to_string(getuid());
- strncpy(uname, tmp, sizeof(uname));
- uname[sizeof(uname) - 1] = '\0';
- xfree(tmp);
- }
- snprintf(buf, i, "CK=dummy67890123456 TS=%u AUTH=%s DT=%s",
- (uint32_t) time(NULL), uname, response);
- checksum(sum, auth_key, (buf+20)); /* overwrite "CK=dummy..." above */
- memcpy(buf, sum, 19);
- i = strlen(buf) + 1;
- (void) _send_msg(new_fd, buf, i);
- xfree(buf);
- }