⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 iscsi.c

📁 这个linux源代码是很全面的~基本完整了~使用c编译的~由于时间问题我没有亲自测试~但就算用来做参考资料也是非常好的
💻 C
📖 第 1 页 / 共 5 页
字号:
}static int iscsi_recvmsg( iscsi_session_t *session, struct msghdr *msg, int len ){    int rc = 0;    mm_segment_t oldfs;    if (session->socket) {        oldfs = get_fs();        set_fs( get_ds() );        /* Try to avoid memory allocation deadlocks by using GFP_ATOMIC. */        session->socket->sk->allocation = GFP_ATOMIC;                    rc = sock_recvmsg( session->socket, msg, len, MSG_WAITALL);        set_fs( oldfs );     }    return rc;}static int iscsi_sendmsg( iscsi_session_t *session, struct msghdr *msg, int len ){    int rc = 0;    mm_segment_t oldfs;    if (session->socket) {        oldfs = get_fs();        set_fs( get_ds() );                /* Try to avoid resource acquisition deadlocks by using GFP_ATOMIC. */        session->socket->sk->allocation = GFP_ATOMIC;        /* FIXME: ought to loop handling short writes, unless a signal occurs */        rc = sock_sendmsg(session->socket, msg, len);                set_fs( oldfs );    }            return rc;}/* create and connect a new socket for this session */int iscsi_connect(iscsi_session_t *session) {    mm_segment_t oldfs;    struct socket           *socket;    struct sockaddr_in      addr;    int window_size;    int arg = 1, arglen = 0;    int rc = 0, ret = 0;    if (session->socket) {        printk("iSCSI: session %p already has socket %p\n", session, session->socket);        return 0;    }    oldfs = get_fs();    set_fs( get_ds() );    if (sock_create(PF_INET, SOCK_STREAM, IPPROTO_TCP, &socket) < 0) {        printk("iSCSI: failed to create socket\n");        set_fs(oldfs);        return 0;    }    /* no delay in sending */    if (socket->ops->setsockopt(socket, IPPROTO_TCP, TCP_NODELAY, (char *)&arg, sizeof(arg)) < 0) {        printk("iSCSI: failed to setsockopt TCP_NODELAY\n");        goto done;    }    /* try to ensure a reasonably sized TCP window */    arglen = sizeof(window_size);    if (sock_getsockopt(socket, SOL_SOCKET, SO_RCVBUF, (char *)&window_size, &arglen) >= 0) {        DEBUG_FLOW1("iSCSI: TCP recv window size %u\n", window_size);                if (session->tcp_window_size && (window_size < session->tcp_window_size)) {            window_size = session->tcp_window_size;            if (sock_setsockopt(socket, SOL_SOCKET, SO_RCVBUF, (char *)&window_size, sizeof(window_size)) < 0) {                printk("iSCSI: failed to set TCP recv window size to %u\n", window_size);            }            else if (sock_getsockopt(socket, SOL_SOCKET, SO_RCVBUF, (char *)&window_size, &arglen) >= 0) {                DEBUG_INIT2("iSCSI: set TCP recv window size to %u, actually got %u\n", session->tcp_window_size, window_size);            }        }    }    else {        printk("iSCSI: getsockopt RCVBUF %p failed\n", socket);    }    if (sock_getsockopt(socket, SOL_SOCKET, SO_SNDBUF, (char *)&window_size, &arglen) >= 0) {        DEBUG_FLOW1("iSCSI: TCP send window size %u\n", window_size);                if (session->tcp_window_size && (window_size < session->tcp_window_size)) {            window_size = session->tcp_window_size;            if (sock_setsockopt(socket, SOL_SOCKET, SO_SNDBUF, (char *)&window_size, sizeof(window_size)) < 0) {                printk("iSCSI: failed to set TCP send window size to %u\n", window_size);            }            else if (sock_getsockopt(socket, SOL_SOCKET, SO_SNDBUF, (char *)&window_size, &arglen) >= 0) {                DEBUG_INIT2("iSCSI: set TCP send window size to %u, actually got %u\n", session->tcp_window_size, window_size);            }        }    }    else {        printk("iSCSI: getsockopt SNDBUF %p failed\n", socket);    }    /* connect to the target */    addr.sin_family = AF_INET;    addr.sin_port = htons(session->port);    if (session->ip_length == 4) {        memcpy(&addr.sin_addr.s_addr, session->ip_address, MIN(sizeof(addr.sin_addr.s_addr), session->ip_length));    }    else {        /* FIXME: IPv6 */        printk("iSCSI: unable to handle IPv6 address, length %u, addr %u.%u.%u.%u\n",                session->ip_length, session->ip_address[0], session->ip_address[1], session->ip_address[2], session->ip_address[3]);        goto done;    }    rc = socket->ops->connect(socket, (struct sockaddr *)&addr, sizeof(addr), 0);    if (signal_pending(current))        goto done;    if (rc < 0) {        char *error = iscsi_strerror(-rc);        if (error && error[0] != '\0') {            printk("iSCSI: session %p to %s failed to connect, rc %d, %s\n", session, session->log_name, rc, error);        }        else {            printk("iSCSI: session %p to %s failed to connect, rc %d\n", session, session->log_name, rc);        }    }    else {        if (LOG_ENABLED(ISCSI_LOG_LOGIN))            printk("iSCSI: session %p to %s connected at %lu\n", session, session->log_name, jiffies);        ret = 1;    } done:    if (ret) {        /* save the socket pointer for later */        session->socket = socket;    }    else {        /* close the socket */        sock_release(socket);        session->socket = NULL;    }    wmb();    set_fs(oldfs);    return ret;}void iscsi_disconnect(iscsi_session_t *session) {    if (session->socket) {#if TCP_ABORT_ON_DROP        if (test_and_clear_bit(SESSION_DROPPED, &session->control_bits) &&             !test_bit(SESSION_LOGGED_OUT, &session->control_bits))        {            /* setting linger on and lingertime to 0 before closing             * the socket will trigger a TCP abort (abort all sends             * and receives, possibly send RST, connection to CLOSED),             * which is probably what we want if we're dropping and             * restarting a session.  A TCP Abort will discard TCP             * data, which is probably a bunch of commands and data             * we'll resend on a new session anyway.  This frees up             * skbuffs, and makes the VM livelock less likely.  When             * we relogin again to the target with the same ISID, the             * target will kill off the old connections on it's side,             * so the FIN handshake should be unnecessary, and there             * are cases where network failures may prevent the FIN             * handshake from completing, so the connection wouldn't             * get cleaned up unless the TCP stack has timeouts for             * some of the TCP states.             */            struct linger ling;            mm_segment_t oldfs;            memset(&ling, 0, sizeof(ling));            ling.l_onoff = 1;            ling.l_linger = 0;                        /* we could adjust the socket linger values directly, but using the sockopt call             * is less likely to break if someone overhauls the socket structure.             */            oldfs = get_fs();            set_fs(get_ds());            if (sock_setsockopt(session->socket, IPPROTO_TCP, SO_LINGER, (char *)&ling, sizeof(ling)) < 0) {                printk("iSCSI: session %p couldn't set lingertime to zero after session drop\n", session);            }            else {                DEBUG_INIT1("iSCSI: session %p set lingertime to zero because of session drop\n", session);            }                        set_fs(oldfs);        }#endif        /* close the socket, triggering either a TCP close or a TCP abort */        sock_release(session->socket);                session->socket = NULL;        wmb();    }}int iscsi_send_pdu(iscsi_session_t *session, struct IscsiHdr *pdu, char *data, int timeout){    struct msghdr msg;    struct iovec iov[3];    char padding[4];    int pad = 0;    int rc;    int pdu_length = 0;    int data_length;    if (pdu == NULL) {        printk("iSCSI: session %p, pdu NULL, can't send PDU header\n", session);        return 0;    }    memset(iov, 0, sizeof(iov));    memset(&msg, 0, sizeof(msg));    msg.msg_iov = iov;    msg.msg_iovlen = 1;        /* pdu header */    iov[0].iov_base = pdu;    iov[0].iov_len = sizeof(*pdu);    pdu_length = sizeof(*pdu);    /* pdu data */    data_length = ntoh24(pdu->dlength);    if (data) {        iov[msg.msg_iovlen].iov_base = data;        iov[msg.msg_iovlen].iov_len = data_length;        msg.msg_iovlen++;        pdu_length += ntoh24(pdu->dlength);    }    else if (data_length) {        printk("iSCSI: session %p pdu %p with dlength %d, but data NULL\n",               session, pdu, data_length);        return 0;    }    /* add any padding needed */    if (pdu_length % PAD_WORD_LEN) {        memset(padding, 0x0, sizeof(padding));        pad = PAD_WORD_LEN - (pdu_length % PAD_WORD_LEN);    }    if (pad) {        iov[msg.msg_iovlen].iov_base = padding;        iov[msg.msg_iovlen].iov_len = pad;        msg.msg_iovlen++;        pdu_length += pad;    }    /* set a timer, though we shouldn't really need one */    if (timeout) {        session->login_phase_timer = jiffies + (timeout * HZ);        wmb();    }    if (LOG_ENABLED(ISCSI_LOG_LOGIN)) {        char *text = data;        char *end = text + ntoh24(pdu->dlength);        int show_text = 0;        if ((pdu->opcode & ISCSI_OPCODE_MASK) == ISCSI_OP_LOGIN_CMD) {            struct IscsiLoginHdr *login_pdu = (struct IscsiLoginHdr *)pdu;            /* show the login phases and tbit */            printk("iSCSI: session %p sending login pdu with current phase %d, next %d, tbit %d, dlength %d at %lu, timeout at %lu (%d seconds)\n",                   session, login_pdu->curr, login_pdu->next, login_pdu->tbit, ntoh24(pdu->dlength),                    jiffies, session->login_phase_timer, session->login_timeout);            show_text = 1;        }        else if ((pdu->opcode & ISCSI_OPCODE_MASK) == ISCSI_OP_TEXT_CMD) {            printk("iSCSI: session %p sending text pdu, dlength %d at %lu, timeout at %lu (%d seconds)\n",                   session, ntoh24(pdu->dlength),                    jiffies, session->login_phase_timer, session->login_timeout);            show_text = 1;        }        else {            printk("iSCSI: session %p sending pdu with opcode 0x%x, dlength %d at %lu, timeout at %lu (%d seconds)\n",                   session, pdu->opcode, ntoh24(pdu->dlength), jiffies, session->login_phase_timer, session->login_timeout);        }        /* show all the text that we're sending */        while (show_text && (text < end)) {            printk("iSCSI: session %p login text: %s\n", session, text);            text += strlen(text);            while ((text < end) && (*text == '\0'))                text++;        }    }    rc = iscsi_sendmsg(session, &msg, pdu_length);    /* clear the timer */    session->login_phase_timer = 0;    wmb();    if (rc != pdu_length) {        char *error;        if ((rc < 0) && (error = iscsi_strerror(-rc)) && (error[0] != '\0'))            printk("iSCSI: session %p failed to send login PDU, rc %d, %s\n", session, rc, iscsi_strerror(-rc));        else            printk("iSCSI: session %p failed to send login PDU, rc %d\n", session, rc);        return 0;    }    DEBUG_FLOW5("iSCSI: session %p sent login pdu %p at %lu, length %d, dlength %d\n",                 session, pdu, jiffies, pdu_length, ntoh24(pdu->dlength));    return 1;}/* try to read an entire login PDU into the buffer, timing out after timeout seconds */int iscsi_recv_pdu(iscsi_session_t *session, struct IscsiHdr *header, int max_header_length, char *data, int max_data_length, int timeout){    struct msghdr msg;    struct iovec iov[2];    char padding[PAD_WORD_LEN];    int rc = 0;    int data_length;    int ret = 0;    if (header == NULL) {        printk("iSCSI: session %p, can't receive PDU header into NULL\n", session);        return 0;    }    if (max_header_length < sizeof(*header)) {        printk("iSCSI: session %p, can't receive %d PDU header bytes into %d byte buffer\n",                session, sizeof(*header), max_header_length);        return 0;    }    /* set the timer to implement the timeout requested */    if (timeout)        session->login_phase_timer = jiffies + (timeout * HZ);    else        session->login_phase_timer = 0;    mb();    if (LOG_ENABLED(ISCSI_LOG_LOGIN)) {        printk("iSCSI: session %p trying to recv login pdu at %lu, timeout at %lu (%d seconds)\n",                session, jiffies, session->login_phase_timer, timeout);    }    /* read the PDU header */    memset(iov, 0, sizeof(iov));    iov[0].iov_base = (void *)header;    iov[0].iov_len = sizeof(*header);    memset(&msg, 0, sizeof(struct msghdr));    msg.msg_iov = iov;    msg.msg_iovlen = 1;        rc = iscsi_recvmsg(session, &msg, sizeof(*header));    /* FIXME: check for additional header segments */    if (signal_pending(current)) {        printk("iSCSI: session %p recv_login_pdu timed out at %lu\n", session, jiffies);        goto done;    }        if (rc != sizeof(*header)) {        if (rc < 0) {            char *error = iscsi_strerror(-rc);            if (error && error[0] != '\0') {                printk("iSCSI: session %p recv_login_pdu failed to recv %d login PDU bytes, rc %d, %s\n",                        session, iov[0].iov_len, rc, iscsi_strerror(-rc));            }            else {                printk("iSCSI: session %p recv_login_pdu failed to recv %d login PDU bytes, rc %d\n",                        session, iov[0].iov_len, rc);            }        }        else if (rc == 0) {            printk("iSCSI: session %p recv_lo

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -