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->usrmsg_callback, 63 info->altmsg_callback); 64 iocom.node_handler = info->node_handler; 65 if (info->noclosealt) 66 iocom.flags &= ~DMSG_IOCOMF_CLOSEALT; 67 if (info->label) { 68 dmsg_iocom_label(&iocom, "%s", info->label); 69 free(info->label); 70 info->label = NULL; 71 } 72 dmsg_iocom_core(&iocom); 73 dmsg_iocom_done(&iocom); 74 75 fprintf(stderr, 76 "iocom on fd %d terminated error rx=%d, tx=%d\n", 77 info->fd, iocom.ioq_rx.error, iocom.ioq_tx.error); 78 close(info->fd); 79 info->fd = -1; /* safety */ 80 if (info->exit_callback) 81 info->exit_callback(info->handle); 82 free(info); 83 84 return (NULL); 85 } 86 87 /************************************************************************ 88 * AUTHENTICATION * 89 ************************************************************************ 90 * 91 * Callback via dmsg_iocom_core(). 92 * 93 * Additional messaging-based authentication must occur before normal 94 * message operation. The connection has already been encrypted at 95 * this point. 96 */ 97 static void master_auth_conn_rx(dmsg_msg_t *msg); 98 99 static 100 void 101 master_auth_signal(dmsg_iocom_t *iocom) 102 { 103 dmsg_msg_t *msg; 104 105 /* 106 * Transmit LNK_CONN, enabling the SPAN protocol if both sides 107 * agree. 108 * 109 * XXX put additional authentication states here? 110 */ 111 msg = dmsg_msg_alloc(&iocom->state0, 0, 112 DMSG_LNK_CONN | DMSGF_CREATE, 113 master_auth_conn_rx, NULL); 114 msg->any.lnk_conn.peer_mask = (uint64_t)-1; 115 msg->any.lnk_conn.peer_type = DMSG_PEER_CLUSTER; 116 msg->any.lnk_conn.pfs_mask = (uint64_t)-1; 117 118 dmsg_msg_write(msg); 119 120 dmsg_iocom_restate(iocom, master_link_signal, master_link_rxmsg); 121 } 122 123 static 124 void 125 master_auth_conn_rx(dmsg_msg_t *msg) 126 { 127 if (msg->any.head.cmd & DMSGF_DELETE) 128 dmsg_msg_reply(msg, 0); 129 } 130 131 static 132 void 133 master_auth_rxmsg(dmsg_msg_t *msg __unused) 134 { 135 } 136 137 /************************************************************************ 138 * POST-AUTHENTICATION SERVICE MSGS * 139 ************************************************************************ 140 * 141 * Callback via dmsg_iocom_core(). 142 */ 143 static 144 void 145 master_link_signal(dmsg_iocom_t *iocom) 146 { 147 dmsg_msg_lnk_signal(iocom); 148 } 149 150 static 151 void 152 master_link_rxmsg(dmsg_msg_t *msg) 153 { 154 dmsg_state_t *state; 155 dmsg_iocom_t *iocom; 156 uint32_t cmd; 157 158 /* 159 * If the message state has a function established we just 160 * call the function, otherwise we call the appropriate 161 * link-level protocol related to the original command and 162 * let it sort it out. 163 * 164 * Non-transactional one-off messages, on the otherhand, 165 * might have REPLY set. 166 */ 167 state = msg->state; 168 iocom = state->iocom; 169 cmd = (state != &iocom->state0) ? state->icmd : msg->any.head.cmd; 170 171 if (state != &iocom->state0 && state->func) { 172 state->func(msg); 173 } else { 174 switch(cmd & DMSGF_PROTOS) { 175 case DMSG_PROTO_LNK: 176 dmsg_msg_lnk(msg); 177 break; 178 case DMSG_PROTO_DBG: 179 dmsg_msg_dbg(msg); 180 break; 181 default: 182 iocom->usrmsg_callback(msg, 1); 183 break; 184 } 185 } 186 } 187 188 /* 189 * This is called from the master node to process a received debug 190 * shell command. We process the command, outputting the results, 191 * then finish up by outputting another prompt. 192 */ 193 void 194 dmsg_msg_dbg(dmsg_msg_t *msg) 195 { 196 dmsg_iocom_t *iocom = msg->state->iocom; 197 198 switch(msg->tcmd & DMSGF_CMDSWMASK) { 199 case DMSG_DBG_SHELL: 200 /* 201 * This is a command which we must process. 202 * When we are finished we generate a final reply. 203 */ 204 if (msg->aux_data) 205 msg->aux_data[msg->aux_size - 1] = 0; 206 iocom->usrmsg_callback(msg, 0); 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 iocom->usrmsg_callback(msg, 1); 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 dmsg_printf() can filter the message (cmd) related 230 * to the dmsg_printf(). We filter out DBG messages. 231 */ 232 void 233 dmsg_printf(dmsg_iocom_t *iocom, 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(&iocom->state0, 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