1 /* 2 * Copyright (c) 2011-2012 The DragonFly Project. All rights reserved. 3 * 4 * This code is derived from software contributed to The DragonFly Project 5 * by Matthew Dillon <dillon@dragonflybsd.org> 6 * by Venkatesh Srinivas <vsrinivas@dragonflybsd.org> 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in 16 * the documentation and/or other materials provided with the 17 * distribution. 18 * 3. Neither the name of The DragonFly Project nor the names of its 19 * contributors may be used to endorse or promote products derived 20 * from this software without specific, prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 23 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 24 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 25 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 26 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 27 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 28 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 29 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 30 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 31 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 32 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 36 #include "dmsg_local.h" 37 38 static void master_auth_signal(dmsg_iocom_t *iocom); 39 static void master_auth_rxmsg(dmsg_msg_t *msg); 40 static void master_link_signal(dmsg_iocom_t *iocom); 41 static void master_link_rxmsg(dmsg_msg_t *msg); 42 43 /* 44 * Service an accepted connection (runs as a pthread) 45 * 46 * (also called from a couple of other places) 47 */ 48 void * 49 dmsg_master_service(void *data) 50 { 51 dmsg_master_service_info_t *info = data; 52 dmsg_iocom_t iocom; 53 54 if (info->detachme) 55 pthread_detach(pthread_self()); 56 57 dmsg_iocom_init(&iocom, 58 info->fd, 59 (info->altmsg_callback ? info->altfd : -1), 60 master_auth_signal, 61 master_auth_rxmsg, 62 info->dbgmsg_callback, 63 info->altmsg_callback); 64 if (info->noclosealt) 65 iocom.flags &= ~DMSG_IOCOMF_CLOSEALT; 66 if (info->label) { 67 dmsg_iocom_label(&iocom, "%s", info->label); 68 free(info->label); 69 info->label = NULL; 70 } 71 dmsg_iocom_core(&iocom); 72 dmsg_iocom_done(&iocom); 73 74 fprintf(stderr, 75 "iocom on fd %d terminated error rx=%d, tx=%d\n", 76 info->fd, iocom.ioq_rx.error, iocom.ioq_tx.error); 77 close(info->fd); 78 info->fd = -1; /* safety */ 79 if (info->exit_callback) 80 info->exit_callback(info->handle); 81 free(info); 82 83 return (NULL); 84 } 85 86 /************************************************************************ 87 * AUTHENTICATION * 88 ************************************************************************ 89 * 90 * Callback via dmsg_iocom_core(). 91 * 92 * Additional messaging-based authentication must occur before normal 93 * message operation. The connection has already been encrypted at 94 * this point. 95 */ 96 static void master_auth_conn_rx(dmsg_msg_t *msg); 97 98 static 99 void 100 master_auth_signal(dmsg_iocom_t *iocom) 101 { 102 dmsg_msg_t *msg; 103 104 /* 105 * Transmit LNK_CONN, enabling the SPAN protocol if both sides 106 * agree. 107 * 108 * XXX put additional authentication states here? 109 */ 110 msg = dmsg_msg_alloc(&iocom->circuit0, 0, 111 DMSG_LNK_CONN | DMSGF_CREATE, 112 master_auth_conn_rx, NULL); 113 msg->any.lnk_conn.peer_mask = (uint64_t)-1; 114 msg->any.lnk_conn.peer_type = DMSG_PEER_CLUSTER; 115 msg->any.lnk_conn.pfs_mask = (uint64_t)-1; 116 117 dmsg_msg_write(msg); 118 119 dmsg_iocom_restate(iocom, 120 master_link_signal, 121 master_link_rxmsg, 122 iocom->altmsg_callback); 123 } 124 125 static 126 void 127 master_auth_conn_rx(dmsg_msg_t *msg) 128 { 129 if (msg->any.head.cmd & DMSGF_DELETE) 130 dmsg_msg_reply(msg, 0); 131 } 132 133 static 134 void 135 master_auth_rxmsg(dmsg_msg_t *msg __unused) 136 { 137 } 138 139 /************************************************************************ 140 * POST-AUTHENTICATION SERVICE MSGS * 141 ************************************************************************ 142 * 143 * Callback via dmsg_iocom_core(). 144 */ 145 static 146 void 147 master_link_signal(dmsg_iocom_t *iocom) 148 { 149 dmsg_msg_lnk_signal(iocom); 150 } 151 152 static 153 void 154 master_link_rxmsg(dmsg_msg_t *msg) 155 { 156 dmsg_state_t *state; 157 uint32_t cmd; 158 159 /* 160 * If the message state has a function established we just 161 * call the function, otherwise we call the appropriate 162 * link-level protocol related to the original command and 163 * let it sort it out. 164 * 165 * Non-transactional one-off messages, on the otherhand, 166 * might have REPLY set. 167 */ 168 state = msg->state; 169 cmd = state ? state->icmd : msg->any.head.cmd; 170 171 if (state && state->func) { 172 assert(state->func != NULL); 173 state->func(msg); 174 } else { 175 switch(cmd & DMSGF_PROTOS) { 176 case DMSG_PROTO_LNK: 177 dmsg_msg_lnk(msg); 178 break; 179 case DMSG_PROTO_DBG: 180 dmsg_msg_dbg(msg); 181 break; 182 default: 183 dmsg_msg_reply(msg, DMSG_ERR_NOSUPP); 184 break; 185 } 186 } 187 } 188 189 /* 190 * This is called from the master node to process a received debug 191 * shell command. We process the command, outputting the results, 192 * then finish up by outputting another prompt. 193 */ 194 void 195 dmsg_msg_dbg(dmsg_msg_t *msg) 196 { 197 switch(msg->any.head.cmd & DMSGF_CMDSWMASK) { 198 case DMSG_DBG_SHELL: 199 /* 200 * This is a command which we must process. 201 * When we are finished we generate a final reply. 202 */ 203 if (msg->aux_data) 204 msg->aux_data[msg->aux_size - 1] = 0; 205 msg->iocom->dbgmsg_callback(msg); 206 dmsg_msg_reply(msg, 0); /* XXX send prompt instead */ 207 break; 208 case DMSG_DBG_SHELL | DMSGF_REPLY: 209 /* 210 * A reply just prints out the string. No newline is added 211 * (it is expected to be embedded if desired). 212 */ 213 if (msg->aux_data) 214 msg->aux_data[msg->aux_size - 1] = 0; 215 if (msg->aux_data) 216 write(2, msg->aux_data, strlen(msg->aux_data)); 217 break; 218 default: 219 dmsg_msg_reply(msg, DMSG_ERR_NOSUPP); 220 break; 221 } 222 } 223 224 /* 225 * Returns text debug output to the original defined by (msg). (msg) is 226 * not modified and stays intact. We use a one-way message with REPLY set 227 * to distinguish between a debug command and debug terminal output. 228 * 229 * To prevent loops circuit_printf() can filter the message (cmd) related 230 * to the circuit_printf(). We filter out DBG messages. 231 */ 232 void 233 dmsg_circuit_printf(dmsg_circuit_t *circuit, const char *ctl, ...) 234 { 235 dmsg_msg_t *rmsg; 236 va_list va; 237 char buf[1024]; 238 size_t len; 239 240 va_start(va, ctl); 241 vsnprintf(buf, sizeof(buf), ctl, va); 242 va_end(va); 243 len = strlen(buf) + 1; 244 245 rmsg = dmsg_msg_alloc(circuit, len, 246 DMSG_DBG_SHELL | DMSGF_REPLY, 247 NULL, NULL); 248 bcopy(buf, rmsg->aux_data, len); 249 250 dmsg_msg_write(rmsg); 251 } 252