/* called when an inotify event is received */ static void process_inotify(int fd) { int bytes; /* union to avoid strict-aliasing problems */ union { char buffer[256]; /* a tad large */ struct inotify_event event; } eventbuf; bytes = read(fd, &eventbuf.buffer, sizeof(eventbuf.buffer)); acpid_log(LOG_DEBUG, "inotify read bytes: %d", bytes); /* eof is not expected */ if (bytes == 0) { acpid_log(LOG_WARNING, "inotify fd eof encountered"); return; } else if (bytes < 0) { /* EINVAL means buffer wasn't big enough. See inotify(7). */ acpid_log(LOG_ERR, "inotify read error: %s (%d)", strerror(errno), errno); acpid_log(LOG_ERR, "disconnecting from inotify"); delete_connection(fd); return; } acpid_log(LOG_DEBUG, "inotify name len: %d", eventbuf.event.len); const int dnsize = 256; char devname[dnsize]; /* if a name is included */ if (eventbuf.event.len > 0) { /* devname = ACPID_INPUTLAYERDIR + "/" + pevent -> name */ strcpy(devname, ACPID_INPUTLAYERDIR); strcat(devname, "/"); strncat(devname, eventbuf.event.name, dnsize - strlen(devname) - 1); } /* if this is a create */ if (eventbuf.event.mask & IN_CREATE) { acpid_log(LOG_DEBUG, "inotify about to open: %s", devname); open_inputfile(devname); } /* if this is a delete */ if (eventbuf.event.mask & IN_DELETE) { /* struct connection *c; */ acpid_log(LOG_DEBUG, "inotify received a delete for: %s", devname); #if 0 /* Switching back to the original ENODEV detection scheme. See process_input() in input_layer.c. */ /* keeping this for future reference */ /* search for the event file in the connection list */ /* ??? Or should we just have a delete_connection_name()? */ c = find_connection_name(devname); /* close that connection if found */ if (c) delete_connection(c->fd); #endif } }
static connection_t * make_connection(session_t * sess, iscsid_login_req_t * req, iscsid_response_t * res, uint32_t * stid) { connection_t *conn; iscsi_login_parameters_t loginp; int sock; int ret; int yes = 1; target_t *target; portal_t *portal = NULL; iscsi_portal_address_t *addr; struct sockaddr_in serverAddress; struct hostent *host; initiator_t *init; DEB(9, ("Make Connection sess=%p, req=%p, res=%p, stid=%p\n", sess, req, res, stid)); (void) memset(&loginp, 0x0, sizeof(loginp)); (void) memset(&serverAddress, 0x0, sizeof(serverAddress)); /* find the target portal */ if (stid != NULL) { send_target_t *starget; if ((starget = find_send_target_id(*stid)) == NULL) { res->status = ISCSID_STATUS_INVALID_TARGET_ID; return NULL; } addr = &starget->addr; target = (target_t *)(void *)starget; } else { if (NO_ID(&req->portal_id) || (portal = find_portal(&req->portal_id)) == NULL) { portal_group_t *group; /* if no ID was specified, use target from existing session */ if (NO_ID(&req->portal_id)) { if (!sess->num_connections || ((target = find_target_id(TARGET_LIST, sess->target.sid.id)) == NULL)) { res->status = ISCSID_STATUS_INVALID_PORTAL_ID; return NULL; } } /* if a target was given instead, use it */ else if ((target = find_target(TARGET_LIST, &req->portal_id)) == NULL) { res->status = ISCSID_STATUS_INVALID_PORTAL_ID; return NULL; } /* now get from target to portal - if this is the first connection, */ /* just use the first portal group. */ if (!sess->num_connections) { group = TAILQ_FIRST(&target->group_list); } /* if it's a second connection, use an available portal in the same */ /* portal group */ else { conn = (connection_t *)(void *) TAILQ_FIRST(&sess->connections); if (conn == NULL || (portal = find_portal_id(conn->portal.sid.id)) == NULL) { res->status = ISCSID_STATUS_INVALID_PORTAL_ID; return NULL; } group = portal->group; } if ((portal = find_free_portal(group)) == NULL) { res->status = ISCSID_STATUS_INVALID_PORTAL_ID; return NULL; } DEB(1, ("find_free_portal returns pid=%d\n", portal->entry.sid.id)); } else target = portal->target; addr = &portal->addr; /* symbolic name for connection? check for duplicates */ if (req->sym_name[0]) { void *p; if (sess->num_connections) p = find_connection_name(sess, req->sym_name); else p = find_session_name(req->sym_name); if (p) { res->status = ISCSID_STATUS_DUPLICATE_NAME; return NULL; } } } if (req != NULL && !NO_ID(&req->initiator_id)) { if ((init = find_initiator(&req->initiator_id)) == NULL) { res->status = ISCSID_STATUS_INVALID_INITIATOR_ID; return NULL; } } else init = select_initiator(); /* translate target address */ DEB(8, ("Connecting to <%s>, port %d\n", addr->address, addr->port)); host = gethostbyname((char *)addr->address); if (host == NULL) { switch (h_errno) { case HOST_NOT_FOUND: res->status = ISCSID_STATUS_HOST_NOT_FOUND; break; case TRY_AGAIN: res->status = ISCSID_STATUS_HOST_TRY_AGAIN; break; default: res->status = ISCSID_STATUS_HOST_ERROR; break; } return NULL; } if (host->h_length > (int)sizeof(serverAddress.sin_addr)) { res->status = ISCSID_STATUS_HOST_ERROR; return NULL; } DEB(8, ("Gethostbyname OK, addrtype %d, len %d, addr %x\n", host->h_addrtype, host->h_length, *((int *) host->h_addr_list[0]))); serverAddress.sin_family = host->h_addrtype; serverAddress.sin_port = htons((addr->port) ? addr->port : ISCSI_DEFAULT_PORT); serverAddress.sin_len = host->h_length; memcpy(&serverAddress.sin_addr, host->h_addr_list[0], host->h_length); /* alloc the connection structure */ conn = calloc(1, sizeof(*conn)); if (conn == NULL) { res->status = ISCSID_STATUS_NO_RESOURCES; return NULL; } /* create and connect the socket */ sock = socket(AF_INET, SOCK_STREAM, 0); if (sock < 0) { free(conn); res->status = ISCSID_STATUS_SOCKET_ERROR; return NULL; } if (init) { if (!bind_socket(sock, init->address)) { close(sock); free(conn); res->status = ISCSID_STATUS_INITIATOR_BIND_ERROR; return NULL; } } DEB(8, ("Connecting socket\n")); if (connect(sock, (struct sockaddr *)(void *)&serverAddress, (socklen_t)sizeof(serverAddress)) < 0) { close(sock); free(conn); res->status = ISCSID_STATUS_CONNECT_ERROR; DEB(1, ("Connecting to socket failed (error %d), returning %d\n", errno, res->status)); return NULL; } /* speed up socket processing */ setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &yes, (socklen_t)sizeof(yes)); /* setup login parameter structure */ loginp.socket = sock; if (target->TargetName[0]) { loginp.is_present.TargetName = 1; loginp.TargetName = target->TargetName; } if (target->options.is_present.MaxConnections) { loginp.is_present.MaxConnections = 1; loginp.MaxConnections = target->options.MaxConnections; } if (target->options.is_present.DataDigest) { loginp.is_present.DataDigest = 1; loginp.DataDigest = target->options.DataDigest; } if (target->options.is_present.HeaderDigest) { loginp.is_present.HeaderDigest = 1; loginp.HeaderDigest = target->options.HeaderDigest; } if (target->options.is_present.DefaultTime2Retain) { loginp.is_present.DefaultTime2Retain = 1; loginp.DefaultTime2Retain = target->options.DefaultTime2Retain; } if (target->options.is_present.DefaultTime2Wait) { loginp.is_present.DefaultTime2Wait = 1; loginp.DefaultTime2Wait = target->options.DefaultTime2Wait; } if (target->options.is_present.ErrorRecoveryLevel) { loginp.is_present.ErrorRecoveryLevel = 1; loginp.ErrorRecoveryLevel = target->options.ErrorRecoveryLevel; } if (target->options.is_present.MaxRecvDataSegmentLength) { loginp.is_present.MaxRecvDataSegmentLength = 1; loginp.MaxRecvDataSegmentLength = target->options.MaxRecvDataSegmentLength; } if (target->auth.auth_info.auth_number) { loginp.is_present.auth_info = 1; loginp.auth_info = target->auth.auth_info; if (target->auth.password[0]) { loginp.is_present.password = 1; loginp.password = target->auth.password; } if (target->auth.target_password[0]) { loginp.is_present.target_password = 1; loginp.target_password = target->auth.target_password; } if (target->auth.user_name[0]) { loginp.is_present.user_name = 1; loginp.user_name = target->auth.user_name; } } loginp.is_present.TargetAlias = 1; loginp.TargetAlias = target->TargetAlias; if (portal != NULL) { /* override general target options with portal options (if specified) */ if (portal->options.is_present.DataDigest) { loginp.is_present.DataDigest = 1; loginp.DataDigest = portal->options.DataDigest; } if (portal->options.is_present.HeaderDigest) { loginp.is_present.HeaderDigest = 1; loginp.HeaderDigest = portal->options.HeaderDigest; } if (portal->options.is_present.MaxRecvDataSegmentLength) { loginp.is_present.MaxRecvDataSegmentLength = 1; loginp.MaxRecvDataSegmentLength = portal->options.MaxRecvDataSegmentLength; } } if (req != NULL) { loginp.session_id = get_id(&list[SESSION_LIST].list, &req->session_id); loginp.login_type = req->login_type; } else loginp.login_type = ISCSI_LOGINTYPE_DISCOVERY; DEB(5, ("Calling Login...\n")); ret = ioctl(driver, (sess != NULL && sess->num_connections) ? ISCSI_ADD_CONNECTION : ISCSI_LOGIN, &loginp); res->status = loginp.status; if (ret) close(sock); if (ret || loginp.status) { free(conn); if (!res->status) res->status = ISCSID_STATUS_GENERAL_ERROR; return NULL; } /* connection established! link connection into session and return IDs */ conn->loginp = loginp; conn->entry.sid.id = loginp.connection_id; if (req != NULL) { strlcpy((char *)conn->entry.sid.name, (char *)req->sym_name, sizeof(conn->entry.sid.name)); } /* Copy important target information */ conn->target.sid = target->entry.sid; strlcpy((char *)conn->target.TargetName, (char *)target->TargetName, sizeof(conn->target.TargetName)); strlcpy((char *)conn->target.TargetAlias, (char *)target->TargetAlias, sizeof(conn->target.TargetAlias)); conn->target.options = target->options; conn->target.auth = target->auth; conn->portal.addr = *addr; conn->session = sess; if (stid == NULL) { iscsid_login_rsp_t *rsp = (iscsid_login_rsp_t *)(void *) res->parameter; sess->entry.sid.id = loginp.session_id; TAILQ_INSERT_TAIL(&sess->connections, &conn->entry, link); sess->num_connections++; res->parameter_length = sizeof(*rsp); rsp->connection_id = conn->entry.sid; rsp->session_id = sess->entry.sid; if (init != NULL) { conn->initiator_id = init->entry.sid.id; init->active_connections++; } } else *stid = loginp.session_id; /* Copy important portal information */ if (portal != NULL) { conn->portal.sid = portal->entry.sid; portal->active_connections++; } return conn; }