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->circuit0, 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 uint32_t cmd; 156 157 /* 158 * If the message state has a function established we just 159 * call the function, otherwise we call the appropriate 160 * link-level protocol related to the original command and 161 * let it sort it out. 162 * 163 * Non-transactional one-off messages, on the otherhand, 164 * might have REPLY set. 165 */ 166 state = msg->state; 167 cmd = state ? state->icmd : msg->any.head.cmd; 168 169 if (state && state->func) { 170 assert(state->func != NULL); 171 state->func(msg); 172 } else { 173 switch(cmd & DMSGF_PROTOS) { 174 case DMSG_PROTO_LNK: 175 dmsg_msg_lnk(msg); 176 break; 177 case DMSG_PROTO_DBG: 178 dmsg_msg_dbg(msg); 179 break; 180 default: 181 msg->iocom->usrmsg_callback(msg, 1); 182 break; 183 } 184 } 185 } 186 187 /* 188 * This is called from the master node to process a received debug 189 * shell command. We process the command, outputting the results, 190 * then finish up by outputting another prompt. 191 */ 192 void 193 dmsg_msg_dbg(dmsg_msg_t *msg) 194 { 195 switch(msg->any.head.cmd & DMSGF_CMDSWMASK) { 196 case DMSG_DBG_SHELL: 197 /* 198 * This is a command which we must process. 199 * When we are finished we generate a final reply. 200 */ 201 if (msg->aux_data) 202 msg->aux_data[msg->aux_size - 1] = 0; 203 msg->iocom->usrmsg_callback(msg, 0); 204 dmsg_msg_reply(msg, 0); /* XXX send prompt instead */ 205 break; 206 case DMSG_DBG_SHELL | DMSGF_REPLY: 207 /* 208 * A reply just prints out the string. No newline is added 209 * (it is expected to be embedded if desired). 210 */ 211 if (msg->aux_data) 212 msg->aux_data[msg->aux_size - 1] = 0; 213 if (msg->aux_data) 214 write(2, msg->aux_data, strlen(msg->aux_data)); 215 break; 216 default: 217 msg->iocom->usrmsg_callback(msg, 1); 218 break; 219 } 220 } 221 222 /* 223 * Returns text debug output to the original defined by (msg). (msg) is 224 * not modified and stays intact. We use a one-way message with REPLY set 225 * to distinguish between a debug command and debug terminal output. 226 * 227 * To prevent loops circuit_printf() can filter the message (cmd) related 228 * to the circuit_printf(). We filter out DBG messages. 229 */ 230 void 231 dmsg_circuit_printf(dmsg_circuit_t *circuit, const char *ctl, ...) 232 { 233 dmsg_msg_t *rmsg; 234 va_list va; 235 char buf[1024]; 236 size_t len; 237 238 va_start(va, ctl); 239 vsnprintf(buf, sizeof(buf), ctl, va); 240 va_end(va); 241 len = strlen(buf) + 1; 242 243 rmsg = dmsg_msg_alloc(circuit, len, 244 DMSG_DBG_SHELL | DMSGF_REPLY, 245 NULL, NULL); 246 bcopy(buf, rmsg->aux_data, len); 247 248 dmsg_msg_write(rmsg); 249 } 250