📄 iscsi-discovery.c
字号:
case ISCSI_OP_ASYNC_MSG:{ struct iscsi_async_msg_hdr *async_hdr = (struct iscsi_async_msg_hdr *) pdu; int dlength = ntoh24(pdu->dlength); short senselen; char logbuf[128]; int i; /* * If we receive an async message stating * the target wants to close the connection, * then don't try to reconnect anymore. * This is reasonable, so we don't log * anything here. */ if ((async_hdr->async_event == ISCSI_ASYNC_MSG_REQUEST_LOGOUT)|| (async_hdr->async_event == ISCSI_ASYNC_MSG_DROPPING_CONNECTION)|| (async_hdr->async_event == ISCSI_ASYNC_MSG_DROPPING_ALL_CONNECTIONS)) { *long_lived=0; break; } /* * Log info about the async message. */ logmsg(AS_NOTICE, "Received Async Msg from target, Event = %d, " "Code = %d, Data Len = %d\n", async_hdr->async_event, async_hdr->async_vcode, dlength); /* * If there was data, print out the first 8 bytes */ if (dlength > 0) { memset(logbuf, 0, sizeof(logbuf)); for (i=0; i<8 && i<dlength; ++i) { sprintf(logbuf+i*5, "0x%02x ", data[i]); } logmsg (AS_NOTICE, " Data[0]-[%d]: %s\n", i<dlength ? dlength-1 : i-1, logbuf); } if (dlength > (sizeof (short))) { senselen = (ntohs(*(short *) (data))); debugmsg(1, " senselen = %d\n", senselen); if (dlength > senselen + 2) { debugmsg(1, " recvd async event : %s\n", data + 2 + senselen); } } *long_lived = 1; /* * Arrange for a rediscovery to occur in the near * future. We use a timer so that we merge * multiple events that occur in rapid succession, * and only rediscover once for each burst of * Async events. */ set_timer(async_timer, 1); if (*active) { debugmsg(4, "discovery process %p received Async " "event while active", process); } else { debugmsg(4, "discovery process %p received Async " "event while idle", process); } process_async_event_text(sendtargets, info, async_timer, process->pipe_fd); break; } case ISCSI_OP_NOOP_IN:{ struct iscsi_nop_in_hdr *nop = (struct iscsi_nop_in_hdr *) pdu; /* * The iSCSI spec doesn't allow Nops on * discovery sessions, but some targets * use them anyway. If we receive one, we * can safely assume that the target * supports long-lived discovery sessions * (otherwise it wouldn't be sending nops * to verify the connection is still * working). */ *long_lived = 1; debugmsg(4,"discovery session to %s:%d received" " Nop-in with itt %u, ttt %u, dlength %u", config->address, config->port, ntohl(nop->itt), ntohl(nop->ttt), ntoh24(nop->dlength)); if (nop->ttt != ISCSI_RSVD_TASK_TAG) { /* reply to the Nop-in */ if (!send_nop_reply(session, nop, data, session->active_timeout)) { logmsg (AS_ERROR, "discovery session to %s:%d " "failed to send Nop reply, " "ttt %u, reconnecting", config->address, config->port, ntohl(nop->ttt)); rc = DISCOVERY_NEED_RECONNECT; goto done; } } break; } case ISCSI_OP_REJECT:{ struct iscsi_reject_hdr *reject = (struct iscsi_reject_hdr *) pdu; int dlength = ntoh24(pdu->dlength); logmsg(AS_ERROR, "reject, dlength=%d, " "data[0]=0x%x\n", dlength, data[0]); logmsg(AS_ERROR, "Received a reject from the target " "with reason code = 0x%x\n", reject->reason); /* * Just attempt to reconnect if we receive a reject */ rc = DISCOVERY_NEED_RECONNECT; goto done; break; } default:{ logmsg(AS_NOTICE, "discovery session to %s:%d received " "unexpected opcode 0x%x", config->address, config->port, pdu->opcode); rc = DISCOVERY_NEED_RECONNECT; goto done; } } done: return(rc);} /* * Make a best effort to logout the session, then disconnect the * socket. */static voidiscsi_logout_and_disconnect(struct iscsi_session * session){ struct iscsi_logout_hdr logout_req; struct iscsi_logout_rsp_hdr logout_resp; int rc; /* * Build logout request header */ memset(&logout_req, 0, sizeof (logout_req)); logout_req.opcode = ISCSI_OP_LOGOUT_CMD | ISCSI_OP_IMMEDIATE; logout_req.flags = ISCSI_FLAG_FINAL | (ISCSI_LOGOUT_REASON_CLOSE_SESSION & ISCSI_FLAG_LOGOUT_REASON_MASK); logout_req.itt = htonl(session->itt); if (++session->itt == ISCSI_RSVD_TASK_TAG) session->itt = 1; logout_req.cmdsn = htonl(session->cmd_sn); logout_req.expstatsn = htonl(++session->exp_stat_sn); /* * Send the logout request */ rc = iscsi_send_pdu(session, (struct iscsi_hdr *)&logout_req, ISCSI_DIGEST_NONE, NULL, ISCSI_DIGEST_NONE, 3); if (!rc) { logmsg(AS_ERROR, "iscsid: iscsi_logout - failed to send logout PDU.\n"); goto done; } /* * Read the logout response */ memset(&logout_resp, 0, sizeof(logout_resp)); rc = iscsi_recv_pdu(session, (struct iscsi_hdr *)&logout_resp, ISCSI_DIGEST_NONE, NULL, 0, ISCSI_DIGEST_NONE, 1); if (!rc) { logmsg(AS_ERROR, "iscsid: logout - failed to receive logout resp\n"); goto done; } if (logout_resp.response != ISCSI_LOGOUT_SUCCESS) { logmsg(AS_ERROR, "iscsid: logout failed - response = 0x%x\n", logout_resp.response); } done: /* * Close the socket. */ iscsi_disconnect(session);}static voidsendtargets_discovery_process(struct iscsi_discovery_process *process){ struct iscsi_sendtargets_config *config = process->entry->config.sendtargets; struct sigaction action; struct iscsi_session *session; struct hostent *hostn = NULL; struct pollfd pfd; struct iscsi_hdr pdu_buffer; struct iscsi_hdr *pdu = &pdu_buffer; char *data = NULL; char *end_of_data; int long_lived = (config->continuous > 0) ? 1 : 0; int lun_inventory_changed = 0; int active = 0; struct timeval connection_timer, async_timer; int timeout; int rc; struct string_buffer sendtargets; struct string_buffer info; uint8_t status_class = 0, status_detail = 0; unsigned int login_failures = 0; int login_delay = 0; char ip_address[16]; char default_port[12]; int ip_length = 0; int port = config->port; /* initial setup */ process->pid = getpid(); debugmsg(1, "sendtargets discovery process %p starting, address %s:%d, " "continuous %d", process, config->address, config->port, config->continuous); memset(&pdu_buffer, 0, sizeof (pdu_buffer)); clear_timer(&connection_timer); clear_timer(&async_timer); /* set SIGTERM, SIGINT to kill the process */ memset(&action, 0, sizeof (struct sigaction)); action.sa_sigaction = NULL; action.sa_flags = 0; action.sa_handler = SIG_DFL; sigaction(SIGTERM, &action, NULL); sigaction(SIGINT, &action, NULL); /* set SIGPIPE to be ignored, so that we get EPIPE */ action.sa_handler = SIG_IGN; sigaction(SIGPIPE, &action, NULL); /* set SIGHUP to request a rediscovery */ action.sa_handler = sighup_handler; sigaction(SIGHUP, &action, NULL); /* check if a signal arrived before we reset the handler */ if (iscsi_process_should_exit()) { debugmsg(1, "sendtargets discovery process %p,address %d:%d " "exiting\n", process, config->address, config->port); exit(0); } /* allocate data buffers for SendTargets data and discovery pipe info */ init_string_buffer(&sendtargets, 32 * 1024); init_string_buffer(&info, 8 * 1024); /* allocate a new session, and initialize default values */ session = init_new_session(config, process); if (session == NULL) { exit(1); } /* resolve the DiscoveryAddress to an IP address */ while (!hostn) { hostn = gethostbyname(config->address); if (hostn) { /* save the resolved address */ port = config->port; ip_length = hostn->h_length; memcpy(&ip_address, hostn->h_addr, MIN(sizeof (ip_address), hostn->h_length)); /* FIXME: IPv6 */ debugmsg(4, "resolved %s to %u.%u.%u.%u\n", config->address, ip_address[0], ip_address[1], ip_address[2], ip_address[3]); } else { errormsg("cannot resolve host name %s", config->address); sleep(1); } if (iscsi_process_should_exit()) { free_session(&session); exit(0); } } sprintf(default_port, "%d", config->port); debugmsg(4, "discovery timeouts: login %d, auth %d, active %d, " "idle %d, ping %d", session->login_timeout, session->auth_timeout, session->active_timeout, session->idle_timeout, session->ping_timeout); /* setup authentication variables for the session*/ rc = setup_authentication(session, config); if (rc == 0) { free_session(&session); exit(0); } set_address: /* * copy the saved address to the session, * undoing any temporary redirect */ session->port = port; session->ip_length = ip_length; memcpy(session->ip_address, ip_address, MIN(sizeof (session->ip_address), ip_length)); reconnect: iscsi_disconnect(session); session->cmd_sn = 1; session->itt = 1; session->portal_group_tag = PORTAL_GROUP_TAG_UNKNOWN; /* * if we're violating the protocol anyway, there's no reason * to be picky about sending keys. */ session->vendor_specific_keys = long_lived; /* slowly back off the frequency of login attempts */ if (login_failures == 0) login_delay = 0; else if (login_failures < 10) login_delay = 1; /* 10 seconds at 1 sec each */ else if (login_failures < 20) login_delay = 2; /* 20 seconds at 2 sec each */ else if (login_failures < 26) login_delay = 5; /* 30 seconds at 5 sec each */ else if (login_failures < 34) login_delay = 15; /* 60 seconds at 15 sec each */ else login_delay = 60; /* after 2 minutes, try once a minute */ if (login_delay) { debugmsg(4, "discovery session to %s:%d sleeping for %d " "seconds before next login attempt", config->address, config->port, login_delay); sleep(login_delay); } if (!iscsi_connect(session)) { /* FIXME: IPv6 */ logmsg(AS_ERROR, "Connection to Discovery Address %u.%u.%u.%u " "failed", session->ip_address[0], session->ip_address[1], session->ip_address[2], session->ip_address[3]); login_failures++; /* If a temporary redirect sent us to something unreachable, * we want to go back to the original IP address, so make sure * we reset the session's IP. */ goto set_address; } logmsg(AS_NOTICE, "Connected to Discovery Address %u.%u.%u.%u", session->ip_address[0], session->ip_address[1], session->ip_address[2], session->ip_address[3]); debugmsg(4, "discovery session to %s:%d starting iSCSI login on fd %d", config->address, config->port, session->socket_fd); status_class = 0; status_detail = 0; switch (iscsi_login (session, buffer_data(&sendtargets), unused_length(&sendtargets), &status_class, &status_detail)) { case LOGIN_OK: break; case LOGIN_IO_ERROR: case LOGIN_WRONG_PORTAL_GROUP: case LOGIN_REDIRECTION_FAILED: /* try again */ /* FIXME: IPv6 */ logmsg(AS_NOTICE, "retrying discovery login to %u.%u.%u.%u", session->ip_address[0], session->ip_address[1], session->ip_address[2], session->ip_address[3]); iscsi_disconnect(session); login_failures++; goto set_address; default: case LOGIN_FAILED: case LOGIN_NEGOTIATION_FAILED: case LOGIN_AUTHENTICATION_FAILED: case LOGIN_VERSION_MISMATCH: case LOGIN_INVALID_PDU: /* FIXME: IPv6 */ logmsg(AS_ERROR, "discovery login to %u.%u.%u.%u failed, giving up", session->ip_address[0], session->ip_address[1], session->ip_address[2], session->ip_address[3]); iscsi_disconnect(session); free_session(&session); exit(0); } /* check the login status */ switch (status_class) { case ISCSI_STATUS_CLS_SUCCESS: /* FIXME: IPv6 */ debugmsg(4, "discovery login success to %u.%u.%u.%u", session->ip_address[0], session->ip_address[1], session->ip_address[2], session->ip_address[3]); login_failures = 0; break; case ISCSI_STATUS_CLS_REDIRECT: switch (status_detail) { /* the session IP address was changed by the login * library, so just try again with this portal * config but the new address. */ case ISCSI_LOGIN_STATUS_TGT_MOVED_TEMP: /* FIXME: IPv6 */ logmsg(AS_NOTICE, "discovery login temporarily redirected to " "%u.%u.%u.%u port %d\n", session->ip_address[0], session->ip_address[1], session->ip_address[2], session->ip_address[3], session->port); goto reconnect; case ISCSI_LOGIN_STATUS_TGT_MOVED_PERM: /* FIXME: IPv6 */ logmsg(AS_NOTICE, "discovery login permanently redirected to " "%u.%u.%u.%u port %d\n", session->ip_address[0], session->ip_address[1], session->ip_address[2], session->ip_address[3], session->port); /* make the new address permanent */ ip_length = session->ip_length; memcpy(ip_address, session->ip_address, MIN(sizeof (ip_address), session->ip_length)); port = session->port; goto reconnect; default: logmsg(AS_ERROR, "discovery login rejected: redirection type " "0x%x not supported\n", status_detail);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -