void conn_fsm(struct connection *c, enum c_event event) { int i, ns; for (i = 0; fsm[i].action != NULL; i++) { if (c->state & fsm[i].state && event == fsm[i].event) { log_debug("conn_fsm[%s]: %s ev %s", c->session->config.SessionName, conn_state(c->state), conn_event(event)); ns = fsm[i].action(c, event); if (ns == -1) /* XXX better please */ fatalx("conn_fsm: action failed"); log_debug("conn_fsm[%s]: new state %s", c->session->config.SessionName, conn_state(ns)); c->state = ns; return; } } log_warnx("conn_fsm[%s]: unhandled state transition [%s, %s]", c->session->config.SessionName, conn_state(c->state), conn_event(event)); fatalx("bork bork bork"); }
/* * []---- * | session_validate -- do what the name says * | * | At this point the connection has processed the login command so that * | we have InitiatorName and ISID at a minimum. Check to see if there * | are other sessions which match. If so, log that one out and proceed with * | this session. If nothing matches, then link this into a global list. * | * | Once we support multiple connections per session need to scan list * | to see if other connection have the same CID. If so, log out that * | connection. * []---- */ Boolean_t session_validate(iscsi_sess_t *s) { iscsi_sess_t *check; queue_prt(s->s_mgmtq, Q_SESS_NONIO, "SES%x %s ISID[%02x%02x%02x%02x%02x%02x]", s->s_num, s->s_i_alias == NULL ? s->s_i_name : s->s_i_alias, s->s_isid[0], s->s_isid[1], s->s_isid[2], s->s_isid[3], s->s_isid[4], s->s_isid[5]); /* * SessionType=Discovery which means no target name and therefore * this is okay. */ if (s->s_t_name == NULL) return (True); (void) pthread_mutex_lock(&sess_mutex); for (check = sess_head; check; check = check->s_next) { /* * Ignore ourselves in this check. */ if (check == s) continue; if ((check->s_t_name == NULL) || (strcmp(check->s_t_name, s->s_t_name) != 0)) continue; if (strcmp(check->s_i_name, s->s_i_name) != 0) continue; if (check->s_conn_head->c_tpgt != s->s_conn_head->c_tpgt) continue; /* * Section 5.3.5 * Session reinstatement is the process of the initiator * logging in with an ISID that is possible active from * the target's perspective. Thus implicitly logging out * the session that corresponds to the ISID and * reinstating a new iSCSI session in its place (with the * same ISID). */ if (bcmp(check->s_isid, s->s_isid, 6) == 0) { queue_prt(s->s_mgmtq, Q_SESS_NONIO, "SES%x Implicit shutdown", check->s_num); if (check->s_conn_head->c_state == S5_LOGGED_IN) conn_state(check->s_conn_head, T8); else conn_state(check->s_conn_head, T7); break; } } (void) pthread_mutex_unlock(&sess_mutex); return (True); }
static int conn_read(BIO *b, char *out, int outl) { int ret=0; BIO_CONNECT *data; data=(BIO_CONNECT *)b->ptr; if (data->state != BIO_CONN_S_OK) { ret=conn_state(b,data); if (ret <= 0) return(ret); } if (out != NULL) { clear_socket_error(); ret=readsocket(b->num,out,outl); BIO_clear_retry_flags(b); if (ret <= 0) { if (BIO_sock_should_retry(ret)) BIO_set_retry_read(b); } } return(ret); }
static int conn_write(BIO *b, const char *in, int inl) { int ret; BIO_CONNECT *data; data=(BIO_CONNECT *)b->ptr; if (data->state != BIO_CONN_S_OK) { ret=conn_state(b,data); if (ret <= 0) return(ret); } clear_socket_error(); ret=writesocket(b->num,in,inl); BIO_clear_retry_flags(b); if (ret <= 0) { if (BIO_sock_should_retry(ret)) BIO_set_retry_write(b); } return(ret); }
static int conn_write(BIO *bio, const char *in, int in_len) { int ret; BIO_CONNECT *data; data = (BIO_CONNECT *)bio->ptr; if (data->state != BIO_CONN_S_OK) { ret = conn_state(bio, data); if (ret <= 0) { return ret; } } bio_clear_socket_error(); ret = send(bio->num, in, in_len, 0); BIO_clear_retry_flags(bio); if (ret <= 0) { if (bio_fd_should_retry(ret)) { BIO_set_retry_write(bio); } } return ret; }
static int conn_read(BIO *bio, char *out, int out_len) { int ret = 0; BIO_CONNECT *data; data = (BIO_CONNECT *)bio->ptr; if (data->state != BIO_CONN_S_OK) { ret = conn_state(bio, data); if (ret <= 0) { return ret; } } bio_clear_socket_error(); ret = recv(bio->num, out, out_len, 0); BIO_clear_retry_flags(bio); if (ret <= 0) { if (bio_fd_should_retry(ret)) { BIO_set_retry_read(bio); } } return ret; }
static long conn_ctrl(BIO *bio, int cmd, long num, void *ptr) { int *ip; long ret = 1; BIO_CONNECT *data; data = (BIO_CONNECT *)bio->ptr; switch (cmd) { case BIO_CTRL_RESET: ret = 0; data->state = BIO_CONN_S_BEFORE; conn_close_socket(bio); bio->flags = 0; break; case BIO_C_DO_STATE_MACHINE: /* use this one to start the connection */ if (data->state != BIO_CONN_S_OK) { ret = (long)conn_state(bio, data); } else { ret = 1; } break; case BIO_C_SET_CONNECT: if (ptr != NULL) { bio->init = 1; if (num == 0) { OPENSSL_free(data->param_hostname); data->param_hostname = BUF_strdup(ptr); if (data->param_hostname == NULL) { ret = 0; } } else if (num == 1) { OPENSSL_free(data->param_port); data->param_port = BUF_strdup(ptr); if (data->param_port == NULL) { ret = 0; } } else { ret = 0; } } break; case BIO_C_SET_NBIO: data->nbio = (int)num; break; case BIO_C_GET_FD: if (bio->init) { ip = (int *)ptr; if (ip != NULL) { *ip = bio->num; } ret = bio->num; } else { ret = -1; } break; case BIO_CTRL_GET_CLOSE: ret = bio->shutdown; break; case BIO_CTRL_SET_CLOSE: bio->shutdown = (int)num; break; case BIO_CTRL_PENDING: case BIO_CTRL_WPENDING: ret = 0; break; case BIO_CTRL_FLUSH: break; case BIO_CTRL_SET_CALLBACK: { #if 0 /* FIXME: Should this be used? -- Richard Levitte */ OPENSSL_PUT_ERROR(BIO, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); ret = -1; #else ret = 0; #endif } break; case BIO_CTRL_GET_CALLBACK: { int (**fptr)(const BIO *bio, int state, int xret); fptr = (int (**)(const BIO *bio, int state, int xret))ptr; *fptr = data->info_callback; } break; default: ret = 0; break; } return (ret); }
/* * []---- * | sess_process -- handle messages from the connection(s) * []---- */ static void * sess_process(void *v) { iscsi_sess_t *s = (iscsi_sess_t *)v; iscsi_conn_t *c; iscsi_cmd_t *cmd; msg_t *m; Boolean_t process = True; mgmt_request_t *mgmt; name_request_t *nr; t10_cmd_t *t10_cmd; char **buf, local_buf[16]; int lun; extern void dataout_callback(t10_cmd_t *t, char *data, size_t *xfer); (void) pthread_mutex_lock(&s->s_mutex); s->s_state = SS_RUNNING; (void) pthread_mutex_unlock(&s->s_mutex); do { m = queue_message_get(s->s_sessq); switch (m->msg_type) { case msg_cmd_send: cmd = (iscsi_cmd_t *)m->msg_data; if (s->s_t10 == NULL) { /* * The value of 0x960 comes from T10. * See SPC-4, revision 1a, section 6.4.2, * table 87 * * XXX Need to rethink how I should do * the callback. */ s->s_t10 = t10_handle_create(s->s_t_name, T10_TRANS_ISCSI, s->s_conn_head->c_tpgt, s->s_conn_head->c_max_burst_len, s->s_t10q, dataout_callback); } if (t10_cmd_create(s->s_t10, cmd->c_lun, cmd->c_scb, cmd->c_scb_len, (transport_t)cmd, &t10_cmd) == False) { queue_prt(s->s_mgmtq, Q_SESS_ERRS, "SES%x FAILED to create cmd", s->s_num); /* * If the command create failed, the T10 layer * will attempt to create a sense buffer * telling the initiator what went wrong. If * that layer was unable to accomplish that * things are really bad and we need to just * close the connection. */ if (cmd->c_t10_cmd != NULL) { queue_message_set( cmd->c_allegiance->c_dataq, 0, msg_cmd_cmplt, t10_cmd); } else conn_state(cmd->c_allegiance, T11); } else { (void) pthread_mutex_lock( &cmd->c_allegiance->c_mutex); if (cmd->c_state != CmdCanceled) { cmd->c_t10_cmd = t10_cmd; (void) t10_cmd_send(s->s_t10, cmd->c_t10_cmd, cmd->c_data, cmd->c_data_len); } else { t10_cmd_state(t10_cmd, T10_Cmd_Event_Canceled); } (void) pthread_mutex_unlock( &cmd->c_allegiance->c_mutex); } break; case msg_cmd_data_out: cmd = (iscsi_cmd_t *)m->msg_data; if (s->s_t10 != NULL) (void) t10_cmd_data(s->s_t10, cmd->c_t10_cmd, cmd->c_offset_out, cmd->c_data, cmd->c_data_len); break; case msg_targ_inventory_change: if (s->s_t10 != NULL) (void) t10_task_mgmt(s->s_t10, InventoryChange, 0, 0); break; case msg_lu_capacity_change: lun = (int)(uintptr_t)m->msg_data; if (s->s_t10 != NULL) (void) t10_task_mgmt(s->s_t10, CapacityChange, lun, 0); break; case msg_reset_targ: if (s->s_t10 != NULL) (void) t10_task_mgmt(s->s_t10, ResetTarget, 0, 0); break; case msg_reset_lu: if (s->s_t10 != NULL) (void) t10_task_mgmt(s->s_t10, ResetLun, (int)(uintptr_t)m->msg_data, 0); break; case msg_shutdown: (void) pthread_mutex_lock(&s->s_mutex); s->s_state = SS_SHUTDOWN_START; (void) pthread_mutex_unlock(&s->s_mutex); /* * Shutdown rquest comming from a connection. Only * shutdown the STE if this is the last connection * for this session. */ c = (iscsi_conn_t *)m->msg_data; if (session_remove_connection(s, c) == True) { queue_prt(s->s_mgmtq, Q_SESS_NONIO, "SES%x Starting shutdown", s->s_num); /* * If this is the last connection for this * session send a message to the SAM-3 layer to * shutdown. */ if (s->s_t10 != NULL) { t10_handle_disable(s->s_t10); } queue_message_set(s->s_t10q, 0, msg_shutdown_rsp, 0); process = False; } else { /* * Since this isn't the last connection for * the session, acknowledge the connection * request now since it's references from * this session have been removed. */ queue_message_set(c->c_dataq, 0, msg_shutdown_rsp, (void *)False); } break; case msg_initiator_name: nr = (name_request_t *)m->msg_data; s->s_i_name = strdup(nr->nr_name); /* * Acknowledge the request by sending back an empty * message. */ queue_message_set(nr->nr_q, 0, msg_initiator_name, 0); break; case msg_initiator_alias: nr = (name_request_t *)m->msg_data; s->s_i_alias = strdup(nr->nr_name); /* * Acknowledge the request by sending back an empty * message. */ queue_message_set(nr->nr_q, 0, msg_initiator_alias, 0); break; case msg_target_name: nr = (name_request_t *)m->msg_data; s->s_t_name = strdup(nr->nr_name); /* * Acknowledge the request by sending back an empty * message. */ queue_message_set(nr->nr_q, 0, msg_target_name, 0); break; case msg_mgmt_rqst: mgmt = (mgmt_request_t *)m->msg_data; m->msg_data = NULL; (void) pthread_mutex_lock(&mgmt->m_resp_mutex); buf = mgmt->m_u.m_resp; if ((s->s_type == SessionNormal) && (mgmt->m_request == mgmt_full_phase_statistics) && (strcmp(s->s_t_name, mgmt->m_targ_name) == 0)) { buf_add_tag(buf, XML_ELEMENT_CONN, Tag_Start); buf_add_tag(buf, s->s_i_name, Tag_String); if (s->s_i_alias != NULL) { xml_add_tag(buf, XML_ELEMENT_ALIAS, s->s_i_alias); } /* * Need to loop through the connections * and create one time_connected tag for * each. This will be needed once MC/S support * is added. */ (void) snprintf(local_buf, sizeof (local_buf), "%d", mgmt->m_time - s->s_conn_head->c_up_at); xml_add_tag(buf, XML_ELEMENT_TIMECON, local_buf); buf_add_tag(buf, XML_ELEMENT_STATS, Tag_Start); t10_targ_stat(s->s_t10, buf); buf_add_tag(buf, XML_ELEMENT_STATS, Tag_End); buf_add_tag(buf, XML_ELEMENT_CONN, Tag_End); } (void) pthread_mutex_unlock(&mgmt->m_resp_mutex); queue_message_set(mgmt->m_q, 0, msg_mgmt_rply, 0); break; default: queue_prt(s->s_mgmtq, Q_SESS_ERRS, "SES%x Unknown msg type (%d) from Connection", s->s_num, m->msg_type); break; } queue_message_free(m); } while (process == True); return (NULL); }
static long conn_ctrl(BIO *b, int cmd, long num, void *ptr) { BIO *dbio; int *ip; const char **pptr; long ret=1; BIO_CONNECT *data; data=(BIO_CONNECT *)b->ptr; switch (cmd) { case BIO_CTRL_RESET: ret=0; data->state=BIO_CONN_S_BEFORE; conn_close_socket(b); b->flags=0; break; case BIO_C_DO_STATE_MACHINE: /* use this one to start the connection */ if (!data->state != BIO_CONN_S_OK) ret=(long)conn_state(b,data); else ret=1; break; case BIO_C_GET_CONNECT: if (ptr != NULL) { pptr=(const char **)ptr; if (num == 0) { *pptr=data->param_hostname; } else if (num == 1) { *pptr=data->param_port; } else if (num == 2) { *pptr= (char *)&(data->ip[0]); } else if (num == 3) { *((int *)ptr)=data->port; } if ((!b->init) || (ptr == NULL)) *pptr="not initialized"; ret=1; } break; case BIO_C_SET_CONNECT: if (ptr != NULL) { b->init=1; if (num == 0) { if (data->param_hostname != NULL) OPENSSL_free(data->param_hostname); data->param_hostname=BUF_strdup(ptr); } else if (num == 1) { if (data->param_port != NULL) OPENSSL_free(data->param_port); data->param_port=BUF_strdup(ptr); } else if (num == 2) { char buf[16]; unsigned char *p = ptr; BIO_snprintf(buf,sizeof buf,"%d.%d.%d.%d", p[0],p[1],p[2],p[3]); if (data->param_hostname != NULL) OPENSSL_free(data->param_hostname); data->param_hostname=BUF_strdup(buf); memcpy(&(data->ip[0]),ptr,4); } else if (num == 3) { char buf[DECIMAL_SIZE(int)+1]; BIO_snprintf(buf,sizeof buf,"%d",*(int *)ptr); if (data->param_port != NULL) OPENSSL_free(data->param_port); data->param_port=BUF_strdup(buf); data->port= *(int *)ptr; } } break; case BIO_C_SET_NBIO: data->nbio=(int)num; break; case BIO_C_GET_FD: if (b->init) { ip=(int *)ptr; if (ip != NULL) *ip=b->num; ret=b->num; } else ret= -1; break; case BIO_CTRL_GET_CLOSE: ret=b->shutdown; break; case BIO_CTRL_SET_CLOSE: b->shutdown=(int)num; break; case BIO_CTRL_PENDING: case BIO_CTRL_WPENDING: ret=0; break; case BIO_CTRL_FLUSH: break; case BIO_CTRL_DUP: { dbio=(BIO *)ptr; if (data->param_port) BIO_set_conn_port(dbio,data->param_port); if (data->param_hostname) BIO_set_conn_hostname(dbio,data->param_hostname); BIO_set_nbio(dbio,data->nbio); /* FIXME: the cast of the function seems unlikely to be a good idea */ (void)BIO_set_info_callback(dbio,(bio_info_cb *)data->info_callback); } break; case BIO_CTRL_SET_CALLBACK: { #if 0 /* FIXME: Should this be used? -- Richard Levitte */ BIOerr(BIO_F_CONN_CTRL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); ret = -1; #else ret=0; #endif } break; case BIO_CTRL_GET_CALLBACK: { int (**fptr)(); fptr=(int (**)())ptr; *fptr=data->info_callback; } break; default: ret=0; break; } return(ret); }