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_router_t *router); 39 static void master_auth_rxmsg(dmsg_msg_t *msg); 40 static void master_link_signal(dmsg_router_t *router); 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, info->fd, -1, 58 master_auth_signal, 59 master_auth_rxmsg, 60 info->dbgmsg_callback, 61 NULL); 62 dmsg_iocom_core(&iocom); 63 64 fprintf(stderr, 65 "iocom on fd %d terminated error rx=%d, tx=%d\n", 66 info->fd, iocom.ioq_rx.error, iocom.ioq_tx.error); 67 close(info->fd); 68 info->fd = -1; /* safety */ 69 if (info->exit_callback) 70 info->exit_callback(info->handle); 71 free(info); 72 73 return (NULL); 74 } 75 76 /************************************************************************ 77 * AUTHENTICATION * 78 ************************************************************************ 79 * 80 * Callback via dmsg_iocom_core(). 81 * 82 * Additional messaging-based authentication must occur before normal 83 * message operation. The connection has already been encrypted at 84 * this point. 85 */ 86 static void master_auth_conn_rx(dmsg_msg_t *msg); 87 88 static 89 void 90 master_auth_signal(dmsg_router_t *router) 91 { 92 dmsg_msg_t *msg; 93 94 /* 95 * Transmit LNK_CONN, enabling the SPAN protocol if both sides 96 * agree. 97 * 98 * XXX put additional authentication states here? 99 */ 100 msg = dmsg_msg_alloc(router, 0, DMSG_LNK_CONN | DMSGF_CREATE, 101 master_auth_conn_rx, NULL); 102 msg->any.lnk_conn.peer_mask = (uint64_t)-1; 103 msg->any.lnk_conn.peer_type = DMSG_PEER_CLUSTER; 104 105 dmsg_msg_write(msg); 106 107 dmsg_router_restate(router, 108 master_link_signal, 109 master_link_rxmsg, 110 NULL); 111 } 112 113 static 114 void 115 master_auth_conn_rx(dmsg_msg_t *msg) 116 { 117 if (msg->any.head.cmd & DMSGF_DELETE) 118 dmsg_msg_reply(msg, 0); 119 } 120 121 static 122 void 123 master_auth_rxmsg(dmsg_msg_t *msg __unused) 124 { 125 } 126 127 /************************************************************************ 128 * POST-AUTHENTICATION SERVICE MSGS * 129 ************************************************************************ 130 * 131 * Callback via dmsg_iocom_core(). 132 */ 133 static 134 void 135 master_link_signal(dmsg_router_t *router) 136 { 137 dmsg_msg_lnk_signal(router); 138 } 139 140 static 141 void 142 master_link_rxmsg(dmsg_msg_t *msg) 143 { 144 dmsg_state_t *state; 145 uint32_t cmd; 146 147 /* 148 * If the message state has a function established we just 149 * call the function, otherwise we call the appropriate 150 * link-level protocol related to the original command and 151 * let it sort it out. 152 * 153 * Non-transactional one-off messages, on the otherhand, 154 * might have REPLY set. 155 */ 156 state = msg->state; 157 cmd = state ? state->msg->any.head.cmd : msg->any.head.cmd; 158 159 fprintf(stderr, "service-receive: %s\n", dmsg_msg_str(msg)); 160 161 if (state && state->func) { 162 assert(state->func != NULL); 163 state->func(msg); 164 } else { 165 switch(cmd & DMSGF_PROTOS) { 166 case DMSG_PROTO_LNK: 167 dmsg_msg_lnk(msg); 168 break; 169 case DMSG_PROTO_DBG: 170 dmsg_msg_dbg(msg); 171 break; 172 default: 173 dmsg_msg_reply(msg, DMSG_ERR_NOSUPP); 174 break; 175 } 176 } 177 } 178 179 /* 180 * This is called from the master node to process a received debug 181 * shell command. We process the command, outputting the results, 182 * then finish up by outputting another prompt. 183 */ 184 void 185 dmsg_msg_dbg(dmsg_msg_t *msg) 186 { 187 switch(msg->any.head.cmd & DMSGF_CMDSWMASK) { 188 case DMSG_DBG_SHELL: 189 /* 190 * This is a command which we must process. 191 * When we are finished we generate a final reply. 192 */ 193 if (msg->aux_data) 194 msg->aux_data[msg->aux_size - 1] = 0; 195 msg->router->dbgmsg_callback(msg); 196 dmsg_msg_reply(msg, 0); 197 break; 198 case DMSG_DBG_SHELL | DMSGF_REPLY: 199 /* 200 * A reply just prints out the string. No newline is added 201 * (it is expected to be embedded if desired). 202 */ 203 if (msg->aux_data) 204 msg->aux_data[msg->aux_size - 1] = 0; 205 if (msg->aux_data) 206 write(2, msg->aux_data, strlen(msg->aux_data)); 207 break; 208 default: 209 dmsg_msg_reply(msg, DMSG_ERR_NOSUPP); 210 break; 211 } 212 } 213 214 /* 215 * Returns text debug output to the original defined by (msg). (msg) is 216 * not modified and stays intact. We use a one-way message with REPLY set 217 * to distinguish between a debug command and debug terminal output. 218 * 219 * To prevent loops router_printf() can filter the message (cmd) related 220 * to the router_printf(). We filter out DBG messages. 221 */ 222 void 223 dmsg_router_printf(dmsg_router_t *router, const char *ctl, ...) 224 { 225 dmsg_msg_t *rmsg; 226 va_list va; 227 char buf[1024]; 228 size_t len; 229 230 va_start(va, ctl); 231 vsnprintf(buf, sizeof(buf), ctl, va); 232 va_end(va); 233 len = strlen(buf) + 1; 234 235 rmsg = dmsg_msg_alloc(router, len, DMSG_DBG_SHELL | DMSGF_REPLY, 236 NULL, NULL); 237 bcopy(buf, rmsg->aux_data, len); 238 239 dmsg_msg_write(rmsg); 240 } 241