Annotation of kernel/kern/netport_tcp.c, revision 1.1

1.1     ! root        1: /*
        !             2:  * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
        !             3:  *
        !             4:  * @APPLE_LICENSE_HEADER_START@
        !             5:  * 
        !             6:  * Portions Copyright (c) 1999 Apple Computer, Inc.  All Rights
        !             7:  * Reserved.  This file contains Original Code and/or Modifications of
        !             8:  * Original Code as defined in and that are subject to the Apple Public
        !             9:  * Source License Version 1.1 (the "License").  You may not use this file
        !            10:  * except in compliance with the License.  Please obtain a copy of the
        !            11:  * License at http://www.apple.com/publicsource and read it before using
        !            12:  * this file.
        !            13:  * 
        !            14:  * The Original Code and all software distributed under the License are
        !            15:  * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
        !            16:  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
        !            17:  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
        !            18:  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
        !            19:  * License for the specific language governing rights and limitations
        !            20:  * under the License.
        !            21:  * 
        !            22:  * @APPLE_LICENSE_HEADER_END@
        !            23:  */
        !            24: 
        !            25: /* 
        !            26:  * Mach Operating System
        !            27:  * Copyright (c) 1989 Carnegie-Mellon University
        !            28:  * Copyright (c) 1988 Carnegie-Mellon University
        !            29:  * Copyright (c) 1987 Carnegie-Mellon University
        !            30:  * All rights reserved.  The CMU software License Agreement specifies
        !            31:  * the terms and conditions for use and redistribution.
        !            32:  */
        !            33: /*
        !            34:  * File:       netport_tcp.c
        !            35:  * Purpose:
        !            36:  *     Front-end to the TCP system for the netport system
        !            37:  *     implementing network IPC in the kernel.
        !            38:  */
        !            39: 
        !            40: /*
        !            41:  * This module is copied from the TCP tranport module of the user-state
        !            42:  * network server, with only a minimum of changes.
        !            43:  */
        !            44: 
        !            45: #import <sys/types.h>
        !            46: #import <sys/socket.h>
        !            47: #import <sys/socketvar.h>
        !            48: #import <netinet/in.h>
        !            49: #import <mach/kern_return.h>
        !            50: #import <mach/port.h>
        !            51: #import <kern/queue.h>
        !            52: #import <kern/lock.h>
        !            53: #import <kern/thread.h>
        !            54: #import <kern/task.h>
        !            55: #import <kern/ipc_netport.h>
        !            56: #import <kern/kern_msg.h>
        !            57: #import <kern/zalloc.h>
        !            58: #import <sys/param.h>
        !            59: #import <kern/xpr.h>
        !            60: #import <mach/vm_param.h>
        !            61: 
        !            62: #ifndef        NULL
        !            63: #define NULL   0
        !            64: #endif NULL
        !            65: 
        !            66: #if    NeXT
        !            67: #define        Debugger(s)     panic(s)
        !            68: #define queue_enter_first      queue_enter_head
        !            69: #else  NeXT
        !            70: #define        Debugger(s)     kdb_kintr()
        !            71: #endif NeXT
        !            72: 
        !            73: /*
        !            74:  * Definitions for compatibility with the network server coding conventions
        !            75:  * and debugging mechanism.
        !            76:  */
        !            77: #define PRIVATE                /**/
        !            78: #define PUBLIC         /**/
        !            79: #define EXPORT         /**/
        !            80: #define BEGIN(name)    {
        !            81: #define END            }
        !            82: #define RETURN(val)    return (val)
        !            83: #define RET            return
        !            84: 
        !            85: #define DEBUG0(a,b,c)                  XPR(XPR_NPTCP,(c,0,0,0,0,0))
        !            86: #define DEBUG1(a,b,c,p1)               XPR(XPR_NPTCP,(c,p1,0,0,0,0))
        !            87: #define DEBUG2(a,b,c,p1,p2)            XPR(XPR_NPTCP,(c,p1,p2,0,0,0))
        !            88: #define DEBUG3(a,b,c,p1,p2,p3)         XPR(XPR_NPTCP,(c,p1,p2,p3,0,0))
        !            89: #define DEBUG4(a,b,c,p1,p2,p3,p4)      XPR(XPR_NPTCP,(c,p1,p2,p3,p4,0))
        !            90: #define DEBUG5(a,b,c,p1,p2,p3,p4,p5)   XPR(XPR_NPTCP,(c,p1,p2,p3,p4,p5))
        !            91: #define DEBUG6(a,b,c,p1,p2,p3,p4,p5,p6)        XPR(XPR_NPTCP,(c,p1,p2,p3,p4,p5))
        !            92: 
        !            93: #define INCSTAT(s)                             /**/
        !            94: #define msg            np_msg
        !            95: #define errno          np_errno
        !            96: #define ERROR(fmt)     {                       \
        !            97:        np_printf fmt;                          \
        !            98:        if (np_flags & NP_DEBUG)                \
        !            99:                Debugger("NP");                 \
        !           100: }
        !           101: static char            np_msg[200];
        !           102: static int             np_errno;
        !           103: 
        !           104: 
        !           105: #define mutex                  slock
        !           106: #define mutex_lock(l)          simple_lock(l)
        !           107: #define mutex_unlock(l)                simple_unlock(l)
        !           108: #define mutex_init(l)          simple_lock_init(l)
        !           109: 
        !           110: typedef int                    kern_cond_t;
        !           111: #define condition_init(c)      /**/
        !           112: #define condition_wait(c,l)    {       \
        !           113:        simple_unlock(l);               \
        !           114:        sleep((caddr_t)c,PZERO+1);      \
        !           115:        simple_lock(l);                 \
        !           116: }
        !           117: #define condition_signal(c)    wakeup((caddr_t)c)
        !           118: 
        !           119: #if    NeXT
        !           120: #else  NeXT
        !           121: extern task_t  first_task;
        !           122: #endif NeXT
        !           123: 
        !           124: /*
        !           125:  * Macros to derive a TCP connection ID from a trid obtained from a client 
        !           126:  * and vice-versa.
        !           127:  */
        !           128: #define SET_TCPID(tcpid,trid)  { (tcpid) = (trid).v1; }
        !           129: #define SET_TRID(trid,tcpid)   { (trid).v1 = (tcpid); }
        !           130: 
        !           131: 
        !           132: /*
        !           133:  * Transaction records.
        !           134:  */
        !           135: typedef struct tcp_trans {
        !           136:        int                     state;  /* see defines below */
        !           137:        unsigned long           trid;
        !           138:        int                     client_id;
        !           139:        kern_msg_t              kmsg;
        !           140:        int                     len;
        !           141:        int                     crypt_level;
        !           142: /*     int                     (*reply_proc)(); */
        !           143:        queue_chain_t   transq; /* list of pending/waiting transactions */
        !           144: } tcp_trans_t, *tcp_trans_ptr_t;
        !           145: 
        !           146: #define TCP_TR_INVALID 0
        !           147: #define TCP_TR_PENDING 1       /* awaiting a reply */
        !           148: #define TCP_TR_WAITING 2       /* awaiting transmission */
        !           149: 
        !           150: zone_t tcp_trans_zone;
        !           151: 
        !           152: 
        !           153: 
        !           154: /*
        !           155:  * Forward declarations.
        !           156:  */
        !           157: void   np_tcp_conn_handler();
        !           158: 
        !           159: 
        !           160: /*
        !           161:  * TCP port to be used by the Mach netport service.
        !           162:  */
        !           163: #define TCP_NETMSG_PORT        2454
        !           164: 
        !           165: 
        !           166: /*
        !           167:  * Debugging flags.
        !           168:  */
        !           169: #define TCP_DBG_MAJOR  (0x1)   /* major events */
        !           170: #define TCP_DBG_CRASH  (0x2)   /* host crashes */
        !           171: #define TCP_DBG_VERBOSE        (0x4)   /* verbose output */
        !           172: 
        !           173: /*
        !           174:  * Connection records.
        !           175:  */
        !           176: typedef        struct tcp_conn {
        !           177:        int                     state;  /* see defines below */
        !           178:        struct socket           *sock;  /* socket structure */
        !           179:        thread_t                th;     /* service thread */
        !           180:        struct mutex            lock;   /* lock for this record */
        !           181:        kern_cond_t             cond;   /* to wake up the service thread */
        !           182:        netaddr_t               dest;   /* peer for current connection */
        !           183:        queue_head_t    trans;  /* list of pending/waiting transactions */
        !           184:        int                     count;  /* number of pending/waiting trans */
        !           185:        queue_chain_t   connq;  /* list of records */
        !           186:        unsigned long           incarn; /* incarnation number */
        !           187:        tcp_ctl_t               ctlbuf; /* for xmit control header */
        !           188: } tcp_conn_t, *tcp_conn_ptr_t;
        !           189: 
        !           190: #define TCP_INVALID    0
        !           191: #define TCP_FREE       1
        !           192: #define TCP_CONNECTED  2
        !           193: #define TCP_OPENING    3
        !           194: #define TCP_CLOSING    4
        !           195: #define TCP_CLOSED     5
        !           196: 
        !           197: /*
        !           198:  * Static declarations.
        !           199:  */
        !           200: PRIVATE tcp_conn_t             conn_vec[32];   /* connection records */
        !           201: 
        !           202: PRIVATE queue_head_t   conn_lru;       /* LRU list of active conn */
        !           203: PRIVATE int                    conn_num;       /* number of active conn */
        !           204: PRIVATE queue_head_t   conn_free;      /* list of free conn */
        !           205: PRIVATE kern_cond_t    conn_cond;      /* to wake up listener */
        !           206: PRIVATE int                    conn_closing;   /* number of conn in TCP_CLOSING */
        !           207: PRIVATE struct mutex           conn_lock;      /* lock for conn_lru & conn_free */
        !           208: 
        !           209: 
        !           210: /*
        !           211:  * Transport IDs are composed of 16 bits for the client side and 16 bits
        !           212:  * for the server side. The client side is just a counter, to be matched
        !           213:  * between the message and the transaction record. The server side is composed
        !           214:  * of 8 bits of index of the connection record in the conn_vec array and
        !           215:  * 8 bits of incarnation number for this connection record.
        !           216:  *
        !           217:  * We can afford not to protect the counter for client-side IDs with a lock,
        !           218:  * because transaction records for one connection are protected by the lock
        !           219:  * that connection, and they never move from one connection to another.
        !           220:  *
        !           221:  * XXX This is not completely foolproof if there is A LOT of traffic,
        !           222:  * but it's cheap.
        !           223:  */
        !           224: PRIVATE unsigned long                  trid_counter;
        !           225: #define cptoix(cp)                     (((cp) - conn_vec)/sizeof(tcp_conn_t))
        !           226: #define ixtocp(id)                     ((tcp_conn_ptr_t)&(conn_vec[(id)]))
        !           227: #define TRID_SET_CLIENT(trid)          { trid = (trid_counter++) & 0xffff; }
        !           228: #define TRID_GET_CLIENT(trid,cl)       { (cl) = (trid) & 0xffff; }
        !           229: #define TRID_SET_SERVER(trid,sv)       { (trid) |= \
        !           230:                                        (cptoix(sv) << 24) | ((sv)->incarn << 16);}
        !           231: #define TRID_GET_SERVER(trid,sv)       { (sv) = ixtocp((trid) >> 24); \
        !           232:                if ((((trid) >> 16) & 0xff) != (sv)->incarn) (sv) = NULL; }
        !           233: 
        !           234: 
        !           235: 
        !           236: /*
        !           237:  * Limits on connected sockets.
        !           238:  */
        !           239: #define TCP_CONN_STEADY                6       /* steady-state max [6] */
        !           240: #define TCP_CONN_OPENING       8       /* max open/opening [8] */
        !           241: #define TCP_CONN_MAX           10      /* absolute maximum [10] */
        !           242: 
        !           243: 
        !           244: /*
        !           245:  * Zone for kmsg's to be used for incoming messages.
        !           246:  */
        !           247: extern zone_t  netport_kmsg_zone;
        !           248: #define DATA_SIZE_MAX                          \
        !           249:                (NETPORT_MSG_SIZE_MAX           \
        !           250:                - sizeof(struct KMsg)           \
        !           251:                + sizeof(tcp_ctl_t)             \
        !           252:                + sizeof(ipc_network_hdr_t)     \
        !           253:                + sizeof(msg_header_t))
        !           254: 
        !           255: 
        !           256: 
        !           257: /*
        !           258:  * Macro for transmission of a simple control message.
        !           259:  *
        !           260:  * cp->lock must be held throughout.
        !           261:  */
        !           262: #define tcp_xmit_control(cp,ctlcode,a_trid,a_code,ret) {       \
        !           263:        int     b_len;                                          \
        !           264:                                                                \
        !           265:        (cp)->ctlbuf.ctl = htonl(ctlcode);                      \
        !           266:        (cp)->ctlbuf.trid = htonl(a_trid);                      \
        !           267:        (cp)->ctlbuf.code = htonl(a_code);                      \
        !           268:        (cp)->ctlbuf.size = 0;                                  \
        !           269:        (cp)->ctlbuf.crypt_level = 0;                           \
        !           270:        b_len = sizeof(tcp_ctl_t);                              \
        !           271:        ret = mach_tcp_send(PORT_NULL,(cp)->sock,               \
        !           272:                                &((cp)->ctlbuf),&b_len,0);      \
        !           273:        INCSTAT(tcp_send);                                      \
        !           274:        DEBUG6(TCP_DBG_VERBOSE,0,2803,cp,ctlcode,a_trid,        \
        !           275:                                        a_code,ret,errno);      \
        !           276: }
        !           277: 
        !           278: /*
        !           279:  * Macro for transmission of data.
        !           280:  *
        !           281:  * cp->lock must be held throughout.
        !           282:  */
        !           283: #define tcp_xmit_data(cp,ctlcode,a_trid,a_code,a_kmsg,a_len,a_crypt,ret) {     \
        !           284:        int             b_len;                                          \
        !           285:                                                                        \
        !           286:        if (a_kmsg) {                                                   \
        !           287:                (a_kmsg)->tcp_ctl.ctl = htonl(ctlcode);                 \
        !           288:                (a_kmsg)->tcp_ctl.trid = htonl(a_trid);                 \
        !           289:                (a_kmsg)->tcp_ctl.code = htonl(a_code);                 \
        !           290:                (a_kmsg)->tcp_ctl.size = htonl(a_len);                  \
        !           291:                (a_kmsg)->tcp_ctl.crypt_level = htonl(a_crypt);         \
        !           292:                                                                        \
        !           293:                DEBUG6(TCP_DBG_VERBOSE,0,2800,cp,ctlcode,a_trid,        \
        !           294:                                        a_code,&a_kmsg,a_crypt);        \
        !           295:                                                                        \
        !           296:                /*                                                      \
        !           297:                 * XXX Worry about data encryption.                     \
        !           298:                 */                                                     \
        !           299:                                                                        \
        !           300:                /*                                                      \
        !           301:                 * Send everything in one pass.                         \
        !           302:                 */                                                     \
        !           303:                b_len = sizeof(tcp_ctl_t) + (a_len);                    \
        !           304:                ret = mach_tcp_send(PORT_NULL,(cp)->sock,               \
        !           305:                                        &((a_kmsg)->tcp_ctl),&b_len,0); \
        !           306:                INCSTAT(tcp_send);                                      \
        !           307:                DEBUG3(TCP_DBG_VERBOSE,0,2801,b_len,ret,errno); \
        !           308:        } else {                                                        \
        !           309:                tcp_xmit_control((cp),(ctlcode),(a_trid),(a_code),(ret));       \
        !           310:        }                                                               \
        !           311: }
        !           312: 
        !           313: 
        !           314: 
        !           315: /*
        !           316:  * np_printf --
        !           317:  *
        !           318:  * Special version of printf to avoid using sprintf in ERROR.
        !           319:  */
        !           320: np_printf(msg,fmt,p1,p2,p3,p4,p5,p6)
        !           321:        char    *msg;
        !           322:        char    *fmt;
        !           323:        int     p1;
        !           324:        int     p2;
        !           325:        int     p3;
        !           326:        int     p4;
        !           327:        int     p5;
        !           328:        int     p6;
        !           329: {
        !           330:        printf(fmt,p1,p2,p3,p4,p5,p6);
        !           331:        printf("\n");
        !           332: }
        !           333: 
        !           334: 
        !           335: 
        !           336: /*
        !           337:  * np_tcp_init_conn --
        !           338:  *
        !           339:  * Allocate and initialize a new TCP connection record.
        !           340:  *
        !           341:  * Parameters:
        !           342:  *
        !           343:  * Results:
        !           344:  *
        !           345:  * pointer to the new record.
        !           346:  *
        !           347:  * Side effects:
        !           348:  *
        !           349:  * Starts a new thread to handle the connection.
        !           350:  *
        !           351:  * Note:
        !           352:  *
        !           353:  * conn_lock must be acquired before calling this routine.
        !           354:  * It is held throughout its execution.
        !           355:  */
        !           356: PRIVATE tcp_conn_ptr_t np_tcp_init_conn()
        !           357: BEGIN("np_tcp_init_conn")
        !           358:        tcp_conn_ptr_t  cp;
        !           359:        int             i;
        !           360:        char            name[40];
        !           361: 
        !           362:        /*
        !           363:         * Find an unused connection record in the conn_vec array.
        !           364:         * We could have used the global memory allocator for that,
        !           365:         * but since there are few connection records, why bother...
        !           366:         *
        !           367:         * conn_lock guarantees mutual exclusion.
        !           368:         */
        !           369:        cp = NULL;
        !           370:        for (i = 0; i < 32; i++) {
        !           371:                if (conn_vec[i].state == TCP_INVALID) {
        !           372:                        cp = &conn_vec[i];
        !           373:                        break;
        !           374:                }
        !           375:        }
        !           376:        if (cp == NULL) {
        !           377:                panic("The TCP module cannot allocate a new connection record");
        !           378:        }
        !           379: 
        !           380:        cp->state = TCP_FREE;
        !           381:        cp->sock = 0;
        !           382:        cp->count = 0;
        !           383:        cp->dest = 0;
        !           384:        mutex_init(&cp->lock);
        !           385:        mutex_lock(&cp->lock);
        !           386:        condition_init(&cp->cond);
        !           387:        queue_init(&cp->trans);
        !           388:        cp->th = NULL;
        !           389: #if    NeXT
        !           390:        (void) kernel_thread(kernel_task,np_tcp_conn_handler);
        !           391: #else  NeX T
        !           392:        (void) kernel_thread(first_task,np_tcp_conn_handler);
        !           393: #endif NeXT
        !           394: /*     sprintf(name,"np_tcp_conn_handler(0x%x)",cp); */
        !           395: 
        !           396:        DEBUG2(TCP_DBG_MAJOR,0,2805,cp,cp->th);
        !           397: 
        !           398:        mutex_unlock(&cp->lock);
        !           399: 
        !           400:        RETURN(cp);
        !           401: END
        !           402: 
        !           403: 
        !           404: 
        !           405: /*
        !           406:  * np_tcp_close_conn --
        !           407:  *
        !           408:  * Arrange to close down one TCP connection as soon as possible.
        !           409:  *
        !           410:  * Parameters:
        !           411:  *
        !           412:  * Results:
        !           413:  *
        !           414:  * Side effects:
        !           415:  *
        !           416:  * Note:
        !           417:  *
        !           418:  * conn_lock must be acquired before calling this routine.
        !           419:  * It is held throughout its execution.
        !           420:  */
        !           421: PRIVATE void np_tcp_close_conn()
        !           422: BEGIN("np_tcp_close_conn")
        !           423:        tcp_conn_ptr_t          first;
        !           424:        tcp_conn_ptr_t          cp;
        !           425:        kern_return_t           ret;
        !           426: 
        !           427:        /*
        !           428:         * Look for an old connection to recycle.
        !           429:         */
        !           430:        first = (tcp_conn_ptr_t)queue_first(&conn_lru);
        !           431:        cp = (tcp_conn_ptr_t)queue_last(&conn_lru);
        !           432:        while (cp != first) {
        !           433:                if (cp->count == 0) {
        !           434:                        mutex_lock(&cp->lock);
        !           435:                        if ((cp->count == 0) && (cp->state == TCP_CONNECTED)) {
        !           436:                                break;
        !           437:                        } else {
        !           438:                                mutex_unlock(&cp->lock);
        !           439:                        }
        !           440:                }
        !           441:                cp = (tcp_conn_ptr_t)queue_prev(&cp->connq);
        !           442:        }
        !           443:        if (cp == first) {
        !           444:                /*
        !           445:                 * We are over-committed. We will try again
        !           446:                 * to close something at the next request or
        !           447:                 * reply.
        !           448:                 *
        !           449:                 * XXX We could also set a timer to kill someone at
        !           450:                 * random, to give new clients a chance.
        !           451:                 */
        !           452:                DEBUG2(TCP_DBG_MAJOR,0,2838,conn_num,conn_closing);
        !           453:        } else {
        !           454:                /*
        !           455:                 * Close this unused connection.
        !           456:                 */
        !           457:                DEBUG4(TCP_DBG_MAJOR,0,2839,cp,cp->dest,conn_num,conn_closing);
        !           458:                cp->state = TCP_CLOSING;
        !           459:                conn_closing++;
        !           460:                tcp_xmit_control(cp,TCP_CTL_CLOSEREQ,0,0,ret);
        !           461:                mutex_unlock(&cp->lock);
        !           462:        }
        !           463: 
        !           464:        RET;
        !           465: END
        !           466: 
        !           467: 
        !           468: 
        !           469: /*
        !           470:  * netport_tcp_sendrequest --
        !           471:  *
        !           472:  * Send a request through the TCP interface.
        !           473:  *
        !           474:  * Parameters:
        !           475:  *
        !           476:  *     client_id       : an identifier assigned by the client to this transaction
        !           477:  *     kmsg            : the data to be sent
        !           478:  *     len             : the length of the data in kmsg
        !           479:  *     to              : the destination of the request
        !           480:  *     crypt_level     : whether the data should be encrypted
        !           481:  *
        !           482:  * Results:
        !           483:  *
        !           484:  *     TR_SUCCESS or a specific failure code.
        !           485:  *
        !           486:  * Side effects:
        !           487:  *
        !           488:  * Design:
        !           489:  *
        !           490:  * Note:
        !           491:  *
        !           492:  */
        !           493: EXPORT int netport_tcp_sendrequest(client_id,kmsg,len,to,crypt_level)
        !           494: int            client_id;
        !           495: kern_msg_t     kmsg;
        !           496: int            len;
        !           497: netaddr_t      to;
        !           498: int            crypt_level;
        !           499: BEGIN("netport_tcp_sendrequest")
        !           500:        tcp_conn_ptr_t          first;
        !           501:        tcp_conn_ptr_t          cp;
        !           502:        tcp_trans_ptr_t         tp;
        !           503:        kern_return_t           ret;
        !           504: 
        !           505:        mutex_lock(&conn_lock);
        !           506:        DEBUG4(TCP_DBG_VERBOSE,0,2837,to,client_id,conn_num,conn_closing);
        !           507:        INCSTAT(tcp_requests_sent);
        !           508: 
        !           509:        /*
        !           510:         * Find an open connection to the destination.
        !           511:         */
        !           512:        first = (tcp_conn_ptr_t)queue_first(&conn_lru);
        !           513:        cp = first;
        !           514:        while (!queue_end(&conn_lru,(queue_entry_t)cp)) {
        !           515:                if (cp->dest == to) {
        !           516:                        break;
        !           517:                }
        !           518:                cp = (tcp_conn_ptr_t)queue_next(&cp->connq);
        !           519:        }
        !           520: 
        !           521:        if (queue_end(&conn_lru,(queue_entry_t)cp)) {
        !           522:                /*
        !           523:                 * Could not find an open connection.
        !           524:                 */
        !           525:                if (conn_num < TCP_CONN_OPENING) {
        !           526:                        /*
        !           527:                         * Immediately start a new connection.
        !           528:                         */
        !           529:                        if (queue_empty(&conn_free)) {
        !           530:                                /*
        !           531:                                 * Initialize a new connection record.
        !           532:                                 */
        !           533:                                cp = np_tcp_init_conn();
        !           534:                        } else {
        !           535:                                cp = (tcp_conn_ptr_t)queue_first(&conn_free);
        !           536:                                queue_remove(&conn_free,cp,
        !           537:                                                        tcp_conn_ptr_t,connq);
        !           538:                        }
        !           539:                        mutex_lock(&cp->lock);
        !           540:                        DEBUG2(TCP_DBG_MAJOR,0,2840,cp,to);
        !           541:                        queue_enter_first(&conn_lru,cp,tcp_conn_ptr_t,connq);
        !           542:                        conn_num++;
        !           543:                        cp->dest = to;
        !           544:                        cp->state = TCP_OPENING;
        !           545:                        cp->count = 1;
        !           546: #ifdef notdef
        !           547:                        /*
        !           548:                         * This is done when placing cp on the free list.
        !           549:                         */
        !           550:                        queue_init(&cp->trans);
        !           551: #endif notdef
        !           552:                        condition_signal(&cp->cond);
        !           553:                        mutex_unlock(&cp->lock);
        !           554:                        if ((conn_num - conn_closing) > TCP_CONN_STEADY) {
        !           555:                                np_tcp_close_conn();
        !           556:                        }
        !           557:                        mutex_unlock(&conn_lock);
        !           558:                } else {
        !           559:                        /*
        !           560:                         * We are over-committed. Tell the caller to wait.
        !           561:                         */
        !           562:                        DEBUG0(TCP_DBG_MAJOR,0,2841);
        !           563:                        if ((conn_num - conn_closing) > TCP_CONN_STEADY) {
        !           564:                                np_tcp_close_conn();
        !           565:                        }
        !           566:                        mutex_unlock(&conn_lock);
        !           567:                        RETURN(TR_OVERLOAD);
        !           568:                }
        !           569:        } else {
        !           570:                /*
        !           571:                 * Found an open connection. Use it!
        !           572:                 */
        !           573:                DEBUG2(TCP_DBG_VERBOSE,0,2842,cp,cp->dest);
        !           574:                if (cp != first) {
        !           575:                        /*
        !           576:                         * Place the record at the head of the queue.
        !           577:                         */
        !           578:                        queue_remove(&conn_lru,cp,tcp_conn_ptr_t,connq);
        !           579:                        queue_enter_first(&conn_lru,cp,tcp_conn_ptr_t,connq);
        !           580:                }
        !           581:                if ((conn_num - conn_closing) > TCP_CONN_STEADY) {
        !           582:                        np_tcp_close_conn();
        !           583:                }
        !           584:                mutex_lock(&cp->lock);
        !           585:                cp->count++;
        !           586:                mutex_unlock(&conn_lock);
        !           587:        }
        !           588: 
        !           589:        /*
        !           590:         * At this point, we have a lock on a connection record for the
        !           591:         * right destination. See if we can transmit the data.
        !           592:         */
        !           593: 
        !           594:        /*
        !           595:         * Link the transaction record in the connection record.
        !           596:         */
        !           597:        ZALLOC(tcp_trans_zone,tp,tcp_trans_ptr_t);
        !           598:        if (tp == NULL) {
        !           599:                panic("netport_tcp_sendrequest: cannot get a transaction record");
        !           600:        }
        !           601:        tp->client_id = client_id;
        !           602:        TRID_SET_CLIENT(tp->trid);
        !           603: 
        !           604:        DEBUG4(TCP_DBG_VERBOSE,0,2843,cp,cp->state,tp,tp->trid);
        !           605: 
        !           606:        if (cp->state == TCP_FREE) {
        !           607:                panic("TCP module trying to transmit on a free connection");
        !           608:        }
        !           609: 
        !           610:        if (cp->state == TCP_CONNECTED) {
        !           611:                /*
        !           612:                 * Send all the data on the socket.
        !           613:                 */
        !           614:                tp->state = TCP_TR_PENDING;
        !           615:                tcp_xmit_data(cp,TCP_CTL_REQUEST,tp->trid,0,kmsg,len,crypt_level,ret);
        !           616:                if (ret != KERN_SUCCESS) {
        !           617:                        /*
        !           618:                         * Something went wrong. Most probably, the client is dead.
        !           619:                         */
        !           620:                        DEBUG2(TCP_DBG_CRASH,0,2844,cp->dest,errno);
        !           621:                        cp->count--;
        !           622:                        mutex_unlock(&cp->lock);
        !           623:                        ZFREE(tcp_trans_zone,tp);
        !           624:                        RETURN(TR_FAILURE);
        !           625:                }
        !           626:        } else {
        !           627:                tp->state = TCP_TR_WAITING;
        !           628:                tp->kmsg = kmsg;
        !           629:                tp->len = len;
        !           630:                tp->crypt_level = crypt_level;
        !           631:        }
        !           632:        queue_enter(&cp->trans,tp,tcp_trans_ptr_t,transq);
        !           633:        mutex_unlock(&cp->lock);
        !           634: 
        !           635:        RETURN(TR_SUCCESS);
        !           636: END
        !           637: 
        !           638: 
        !           639: 
        !           640: /*
        !           641:  * netport_tcp_sendreply --
        !           642:  *
        !           643:  * Send a response through the TCP interface.
        !           644:  *
        !           645:  * Parameters:
        !           646:  *
        !           647:  *     trid            : transport-level ID for a previous operation on this
        !           648:  *                       transaction
        !           649:  *     code            : a return code to be passed to the client.
        !           650:  *     kmsg            : the data to be sent
        !           651:  *     len             : the length of the data in kmsg
        !           652:  *     crypt_level     : whether the data should be encrypted
        !           653:  *
        !           654:  * Results:
        !           655:  *
        !           656:  *     TR_SUCCESS or a specific failure code.
        !           657:  *
        !           658:  * Side effects:
        !           659:  *
        !           660:  * Design:
        !           661:  *
        !           662:  * Note:
        !           663:  *
        !           664:  */
        !           665: EXPORT int netport_tcp_sendreply(trid,code,kmsg,len,crypt_level)
        !           666: trid_t         trid;
        !           667: int            code;
        !           668: kern_msg_t     kmsg;
        !           669: int            len;
        !           670: int            crypt_level;
        !           671: BEGIN("netport_tcp_sendreply")
        !           672:        tcp_conn_ptr_t  cp;
        !           673:        kern_return_t   ret;
        !           674:        int             tcpid;
        !           675: 
        !           676:        SET_TCPID(tcpid,trid);
        !           677:        TRID_GET_SERVER(tcpid,cp);
        !           678: 
        !           679:        /*
        !           680:         * If the client has died, the connection record may
        !           681:         * already have been reused, and we may be sending this reply
        !           682:         * to the wrong machine. This should be detected by the 
        !           683:         * incarnation number in the trid.
        !           684:         */
        !           685:        if (cp == NULL) {
        !           686:                DEBUG1(TCP_DBG_CRASH,0,2847,tcpid);
        !           687:                RETURN(TR_FAILURE);
        !           688:        }
        !           689: 
        !           690:        mutex_lock(&cp->lock);
        !           691: 
        !           692:        DEBUG4(TCP_DBG_VERBOSE,0,2845,tcpid,cp,cp->dest,cp->state);
        !           693:        INCSTAT(tcp_replies_sent);
        !           694: 
        !           695:        if (cp->state != TCP_CONNECTED) {
        !           696:                /*
        !           697:                 * The client has died or the connection has just
        !           698:                 * been dropped. Drop the reply.
        !           699:                 */
        !           700:                mutex_unlock(&cp->lock);
        !           701:                RETURN(TR_FAILURE);
        !           702:        }
        !           703: 
        !           704:        cp->count--;
        !           705:        tcp_xmit_data(cp,TCP_CTL_REPLY,tcpid,code,kmsg,len,crypt_level,ret);
        !           706: 
        !           707:        if (ret != KERN_SUCCESS) {
        !           708:                /*
        !           709:                 * Something went wrong. Most probably, the client is dead.
        !           710:                 */
        !           711:                DEBUG2(TCP_DBG_CRASH,0,2846,cp->dest,errno);
        !           712:                mutex_unlock(&cp->lock);
        !           713:                RETURN(TR_FAILURE);
        !           714:        }
        !           715: 
        !           716:        mutex_unlock(&cp->lock);
        !           717: 
        !           718:        /*
        !           719:         * Update the LRU list of active connections and check for
        !           720:         * excess connections.
        !           721:         */
        !           722:        mutex_lock(&conn_lock);
        !           723:        if (cp != (tcp_conn_ptr_t)queue_first(&conn_lru)) {
        !           724:                /*
        !           725:                 * Place the record at the head of the queue.
        !           726:                 */
        !           727:                queue_remove(&conn_lru,cp,tcp_conn_ptr_t,connq);
        !           728:                queue_enter_first(&conn_lru,cp,tcp_conn_ptr_t,connq);
        !           729:        }
        !           730:        if ((conn_num - conn_closing) > TCP_CONN_STEADY) {
        !           731:                np_tcp_close_conn();
        !           732:        }
        !           733:        mutex_unlock(&conn_lock);
        !           734: 
        !           735:        RETURN(TR_SUCCESS);
        !           736: END
        !           737: 
        !           738: 
        !           739: 
        !           740: /*
        !           741:  * np_tcp_conn_handler_open --
        !           742:  *
        !           743:  * Handler for one connection - opening phase.
        !           744:  *
        !           745:  * Parameters:
        !           746:  *
        !           747:  * cp: pointer to the connection record.
        !           748:  *
        !           749:  * Results:
        !           750:  *
        !           751:  * TRUE if the connection was successfully opened, FALSE otherwise.
        !           752:  *
        !           753:  * Side effects:
        !           754:  *
        !           755:  * Transactions waiting in the connection record are initiated.
        !           756:  *
        !           757:  * Note:
        !           758:  *
        !           759:  * cp->lock must be locked on entry. It is also locked on exit, but
        !           760:  * it may be unlocked during the execution of this procedure.
        !           761:  */
        !           762: PRIVATE boolean_t np_tcp_conn_handler_open(cp)
        !           763:        tcp_conn_ptr_t  cp;
        !           764: BEGIN("np_tcp_conn_handler_open")
        !           765:        tcp_trans_ptr_t         tp;
        !           766:        struct socket           *cs;
        !           767:        struct sockaddr_in      sname;
        !           768: /*     netaddr_t               peeraddr; */
        !           769:        kern_return_t           ret;
        !           770: 
        !           771:        sname.sin_family = AF_INET;
        !           772:        sname.sin_port = htons(TCP_NETMSG_PORT);
        !           773:        sname.sin_addr.s_addr = (u_long)(cp->dest);
        !           774: /*     peeraddr = cp->dest; */
        !           775: 
        !           776:        /*
        !           777:         * Unlock the record while we are waiting for the connection
        !           778:         * to be established.
        !           779:         */
        !           780:        mutex_unlock(&cp->lock);
        !           781: 
        !           782:        mutex_lock(&conn_lock);
        !           783:        ret = mach_tcp_socket(PORT_NULL,&cs);
        !           784:        mutex_unlock(&conn_lock);
        !           785:        if (ret != KERN_SUCCESS) {
        !           786:                ERROR((msg,"np_tcp_conn_handler.socket failed: errno=%d",errno));
        !           787:                panic("tcp");
        !           788:        }
        !           789: 
        !           790:        if (np_flags & NP_SODEBUG) {
        !           791:                cs->so_options |= SO_DEBUG;
        !           792:        }
        !           793: 
        !           794:        ret = mach_tcp_connect(PORT_NULL,cs,&sname,sizeof(struct sockaddr_in));
        !           795:        if (ret != KERN_SUCCESS) {
        !           796:                DEBUG2(TCP_DBG_CRASH,0,2815,0,errno);
        !           797:                mutex_lock(&cp->lock);
        !           798:                RETURN(FALSE);
        !           799:        }
        !           800:        INCSTAT(tcp_connect);
        !           801: 
        !           802:        mutex_lock(&cp->lock);
        !           803:        cp->sock = cs;
        !           804:        cp->state = TCP_CONNECTED;
        !           805:        DEBUG3(TCP_DBG_VERBOSE,0,2816,cp,cs,0);
        !           806: 
        !           807:        /*
        !           808:         * Look for transactions waiting to be transmitted.
        !           809:         */
        !           810:        tp = (tcp_trans_ptr_t)queue_first(&cp->trans);
        !           811:        while (!queue_end(&cp->trans,(queue_entry_t)tp)) {
        !           812:                DEBUG2(TCP_DBG_VERBOSE,0,2817,tp,tp->state);
        !           813:                if (tp->state == TCP_TR_WAITING) {
        !           814:                        tp->state = TCP_TR_PENDING;
        !           815:                        tcp_xmit_data(cp,TCP_CTL_REQUEST,tp->trid,0,
        !           816:                                        tp->kmsg,tp->len,tp->crypt_level,ret);
        !           817:                        if (ret != KERN_SUCCESS) {
        !           818:                                RETURN(FALSE);
        !           819:                        }
        !           820:                }
        !           821:                tp = (tcp_trans_ptr_t)queue_next(&tp->transq);
        !           822:        }
        !           823: 
        !           824:        RETURN(TRUE);
        !           825: END
        !           826: 
        !           827: 
        !           828: 
        !           829: /*
        !           830:  * np_tcp_conn_handler_active --
        !           831:  *
        !           832:  * Handler for one connection - active phase.
        !           833:  *
        !           834:  * Parameters:
        !           835:  *
        !           836:  * cp: pointer to the connection record.
        !           837:  *
        !           838:  * Results:
        !           839:  *
        !           840:  * Exits when the connection should be closed.
        !           841:  *
        !           842:  * Note:
        !           843:  *
        !           844:  * For now, the data received on the connection is only kept until the
        !           845:  * higher-level handler procedure (disp_in_request or reply_proc) returns.
        !           846:  * This allows the use of a data buffer on the stack.
        !           847:  *
        !           848:  */
        !           849: PRIVATE void np_tcp_conn_handler_active(cp)
        !           850:        tcp_conn_ptr_t  cp;
        !           851: BEGIN("np_tcp_conn_handler_active")
        !           852:        struct socket           *cs;
        !           853:        netaddr_t               peeraddr;
        !           854:        tcp_trans_ptr_t         tp;
        !           855:        kern_return_t           ret;
        !           856:        kern_msg_t              kmsg;
        !           857:        kern_msg_t              new_kmsg;
        !           858:        int                     len;
        !           859:        caddr_t                 bufp;           /* current location in data */
        !           860:        int                     buf_count;      /* data available in buf */
        !           861:        int                     buf_free;       /* free space in buf */
        !           862:        int                     data_size;
        !           863:        unsigned long           trid;
        !           864:        trid_t                  trid_cl;
        !           865:        int                     s;
        !           866: 
        !           867:        peeraddr = cp->dest;    /* OK not to lock at this point */
        !           868:        cs = cp->sock;
        !           869:        new_kmsg = NULL;
        !           870: 
        !           871:        /*
        !           872:         * Enter the recv loop.
        !           873:         */
        !           874:        for (;;) {
        !           875: 
        !           876:                /*
        !           877:                 * Get a fresh kmsg for a receive buffer.
        !           878:                 */
        !           879:                if (new_kmsg == NULL) {
        !           880:                        ZALLOC(netport_kmsg_zone,kmsg,kern_msg_t);
        !           881:                        if (kmsg == NULL) {
        !           882:                                panic("netport out of kmsgs");
        !           883:                        }
        !           884:                        kmsg->home_zone = netport_kmsg_zone;
        !           885:                        bufp = (caddr_t)&(kmsg->tcp_ctl);
        !           886:                        buf_count = 0;
        !           887:                        buf_free = DATA_SIZE_MAX;
        !           888:                } else {
        !           889:                        /*
        !           890:                         * There is already some data obtained
        !           891:                         * in the previous pass.
        !           892:                         */
        !           893:                        kmsg = new_kmsg;
        !           894:                }
        !           895:                
        !           896:                /*
        !           897:                 * Get at least a tcp control header in the
        !           898:                 * buffer.
        !           899:                 */
        !           900:                while (buf_count < sizeof(tcp_ctl_t)) {
        !           901:                        len = buf_free;
        !           902:                        ret = mach_tcp_recv(PORT_NULL,cs,bufp,&len,0);
        !           903:                        if ((ret != KERN_SUCCESS) || (len <= 0)) {
        !           904:                                ZFREE(netport_kmsg_zone,kmsg);
        !           905:                                RET;
        !           906:                        }
        !           907:                        INCSTAT(tcp_recv);
        !           908:                        DEBUG2(TCP_DBG_VERBOSE,0,2820,ret,peeraddr);
        !           909:                        buf_count += len;
        !           910:                        buf_free -= len;
        !           911:                        bufp += len;
        !           912:                }
        !           913: 
        !           914:                /*
        !           915:                 * Do all the required byte-swapping (Sigh!).
        !           916:                 */
        !           917:                kmsg->tcp_ctl.ctl               = ntohl(kmsg->tcp_ctl.ctl);
        !           918:                kmsg->tcp_ctl.trid              = ntohl(kmsg->tcp_ctl.trid);
        !           919:                kmsg->tcp_ctl.code              = ntohl(kmsg->tcp_ctl.code);
        !           920:                kmsg->tcp_ctl.size              = ntohl(kmsg->tcp_ctl.size);
        !           921:                kmsg->tcp_ctl.crypt_level       = ntohl(kmsg->tcp_ctl.crypt_level);
        !           922: 
        !           923:                /*
        !           924:                 * Read any user data.
        !           925:                 * Advance the current data pointer.
        !           926:                 */
        !           927:                buf_count -= sizeof(tcp_ctl_t);
        !           928:                data_size = kmsg->tcp_ctl.size;
        !           929:                if (data_size > (buf_count + buf_free)) {
        !           930:                        ERROR((msg,"Netport: size too big from 0x%x\n", peeraddr));
        !           931:                        ZFREE(netport_kmsg_zone,kmsg);
        !           932:                        RET;
        !           933:                }
        !           934:                while (buf_count < data_size) {
        !           935:                        len = buf_free;
        !           936:                        ret = mach_tcp_recv(PORT_NULL,cs,bufp,&len,0);
        !           937:                        if ((ret != KERN_SUCCESS) || (len <= 0)) {
        !           938:                                ZFREE(netport_kmsg_zone,kmsg);
        !           939:                                RET;
        !           940:                        }
        !           941:                        INCSTAT(tcp_recv);
        !           942:                        buf_count += len;
        !           943:                        buf_free -= len;
        !           944:                        bufp += len;
        !           945:                }
        !           946: 
        !           947:                /*
        !           948:                 * If we received more data than we asked for,
        !           949:                 * transfer the excess in a new kmsg.
        !           950:                 */
        !           951:                if (buf_count > data_size) {
        !           952:                        ZALLOC(netport_kmsg_zone,new_kmsg,kern_msg_t);
        !           953:                        if (new_kmsg == NULL) {
        !           954:                                panic("netport out of kmsgs");
        !           955:                        }
        !           956:                        new_kmsg->home_zone = netport_kmsg_zone;
        !           957:                        bcopy(((caddr_t)&(kmsg->netmsg_hdr)) + data_size,
        !           958:                                                (caddr_t)&(new_kmsg->tcp_ctl), 
        !           959:                                                buf_count - data_size);
        !           960:                        buf_count -= data_size;
        !           961:                        bufp = (caddr_t)(&(new_kmsg->tcp_ctl)) + buf_count;
        !           962:                        buf_free = DATA_SIZE_MAX - buf_count;
        !           963:                } else {
        !           964:                        new_kmsg = NULL;
        !           965:                }
        !           966: 
        !           967:                /*
        !           968:                 * XXX Worry about encryption.
        !           969:                 */
        !           970: 
        !           971:                /*
        !           972:                 * Now process the message.
        !           973:                 */
        !           974:                DEBUG1(TCP_DBG_VERBOSE,0,2826,kmsg->tcp_ctl.ctl);
        !           975:                switch(kmsg->tcp_ctl.ctl) {
        !           976:                        case TCP_CTL_REQUEST:
        !           977:                                INCSTAT(tcp_requests_rcvd);
        !           978:                                mutex_lock(&cp->lock);
        !           979:                                cp->count++;
        !           980:                                if (cp->state == TCP_CLOSING) {
        !           981:                                        cp->state = TCP_CONNECTED;
        !           982:                                        mutex_unlock(&cp->lock);
        !           983:                                        mutex_lock(&conn_lock);
        !           984:                                        conn_closing--;
        !           985:                                        mutex_unlock(&conn_lock);
        !           986:                                } else {
        !           987:                                        mutex_unlock(&cp->lock);
        !           988:                                }
        !           989:                                trid = kmsg->tcp_ctl.trid;
        !           990:                                TRID_SET_SERVER(trid,cp);
        !           991:                                SET_TRID(trid_cl,trid);
        !           992:                                (void) netport_handle_rq(TR_TCP_ENTRY,trid_cl,
        !           993:                                                kmsg,data_size,peeraddr,
        !           994:                                                kmsg->tcp_ctl.crypt_level,FALSE);
        !           995:                                /*
        !           996:                                 * The kmsg will be destroyed by netmsg_input_rq.
        !           997:                                 */
        !           998: #ifdef notdef
        !           999:                                if (disp_ret != DISP_WILL_REPLY) {
        !          1000:                                        mutex_lock(&cp->lock);
        !          1001:                                        DEBUG3(TCP_DBG_VERBOSE,0,2827,peeraddr,
        !          1002:                                                                trid,disp_ret);
        !          1003:                                        tcp_xmit_control(cp,TCP_CTL_REPLY,trid,
        !          1004:                                                                disp_ret,ret);
        !          1005:                                        cp->count--;
        !          1006:                                        mutex_unlock(&cp->lock);
        !          1007:                                        if (ret != KERN_SUCCESS) {
        !          1008:                                                RET;
        !          1009:                                        }
        !          1010:                                }
        !          1011: #endif notdef
        !          1012:                                break;
        !          1013: 
        !          1014:                        case TCP_CTL_REPLY:
        !          1015:                                INCSTAT(tcp_replies_rcvd);
        !          1016:                                mutex_lock(&cp->lock);
        !          1017:                                if (cp->state == TCP_CLOSING) {
        !          1018:                                        cp->state = TCP_CONNECTED;
        !          1019:                                        mutex_unlock(&cp->lock);
        !          1020:                                        mutex_lock(&conn_lock);
        !          1021:                                        conn_closing--;
        !          1022:                                        mutex_unlock(&conn_lock);
        !          1023:                                        mutex_lock(&cp->lock);
        !          1024:                                }
        !          1025:                                /*
        !          1026:                                 * Find the transaction record.
        !          1027:                                 */
        !          1028:                                TRID_GET_CLIENT(kmsg->tcp_ctl.trid,trid);
        !          1029:                                tp = (tcp_trans_ptr_t)queue_first(&cp->trans);
        !          1030:                                while (!queue_end(&cp->trans,(queue_entry_t)tp)) {
        !          1031:                                        if (tp->trid == trid) {
        !          1032:                                                break;
        !          1033:                                        }
        !          1034:                                        tp = (tcp_trans_ptr_t)queue_next(&tp->transq);
        !          1035:                                }
        !          1036:                                if (queue_end(&cp->trans,(queue_entry_t)tp)) {
        !          1037:                                        ERROR((msg,
        !          1038: "np_tcp_conn_handler_active: cannot find the transaction record for a reply"));
        !          1039:                                        mutex_unlock(&cp->lock);
        !          1040:                                        ZFREE(netport_kmsg_zone,kmsg);
        !          1041:                                } else {
        !          1042:                                        queue_remove(&cp->trans,tp,
        !          1043:                                                        tcp_trans_ptr_t,transq);
        !          1044:                                        cp->count--;
        !          1045:                                        mutex_unlock(&cp->lock);
        !          1046:                                        DEBUG1(TCP_DBG_VERBOSE,0,2828,tp);
        !          1047:                                        netport_handle_rp(tp->client_id,
        !          1048:                                                kmsg->tcp_ctl.code,kmsg,data_size);
        !          1049:                                        /*
        !          1050:                                         * The kmsg will be destroyed by
        !          1051:                                         * the reply_proc.
        !          1052:                                         */
        !          1053:                                        ZFREE(tcp_trans_zone,tp);
        !          1054:                                }
        !          1055:                                break;
        !          1056: 
        !          1057:                        case TCP_CTL_CLOSEREQ:
        !          1058:                                mutex_lock(&cp->lock);
        !          1059:                                if (cp->count == 0) {
        !          1060:                                        /*
        !          1061:                                         * Send CLOSEREP.
        !          1062:                                         */
        !          1063:                                        DEBUG1(TCP_DBG_MAJOR,0,2829,cp->dest);
        !          1064:                                        tcp_xmit_control(cp,TCP_CTL_CLOSEREP,
        !          1065:                                                                        0,0,ret);
        !          1066:                                        if (cp->state != TCP_CLOSING) {
        !          1067:                                                cp->state = TCP_CLOSED;
        !          1068:                                        }
        !          1069:                                        mutex_unlock(&cp->lock);
        !          1070:                                        ZFREE(netport_kmsg_zone,kmsg);
        !          1071:                                        RET;
        !          1072:                                } else {
        !          1073:                                        /*
        !          1074:                                         * We have some data in
        !          1075:                                         * transit. Nothing more
        !          1076:                                         * should be needed.
        !          1077:                                         */
        !          1078:                                        DEBUG2(TCP_DBG_MAJOR,0,2830,cp->dest,
        !          1079:                                                                        cp->count);
        !          1080:                                        cp->state = TCP_CONNECTED;
        !          1081:                                        mutex_unlock(&cp->lock);
        !          1082:                                        ZFREE(netport_kmsg_zone,kmsg);
        !          1083:                                }
        !          1084:                                break;
        !          1085: 
        !          1086:                        case TCP_CTL_CLOSEREP:
        !          1087:                                mutex_lock(&cp->lock);
        !          1088:                                DEBUG1(TCP_DBG_MAJOR,0,2831,cp->dest);
        !          1089:                                /*
        !          1090:                                 * cp->state can only be TCP_CLOSING:
        !          1091:                                 *
        !          1092:                                 * We have sent a CLOSEREQ, and set the
        !          1093:                                 * state to TCP_CLOSING then. If the state
        !          1094:                                 * has changed since then, it must be because
        !          1095:                                 * we have received data. But this data can only
        !          1096:                                 * be a request, because we had nothing going on
        !          1097:                                 * when we sent the CLOSEREQ. This CLOSEREQ must
        !          1098:                                 * arrive at the other end before our reply
        !          1099:                                 * because TCP does not reorder messages. But
        !          1100:                                 * then the CLOSEREQ will be rejected because
        !          1101:                                 * of the pending transaction.
        !          1102:                                 */
        !          1103:                                mutex_unlock(&cp->lock);
        !          1104:                                ZFREE(netport_kmsg_zone,kmsg);
        !          1105:                                RET;
        !          1106: 
        !          1107:                        default:
        !          1108:                                ERROR((msg,
        !          1109:                "np_tcp_conn_handler_active: received an unknown ctl code: %d",
        !          1110:                                                                kmsg->tcp_ctl.ctl));
        !          1111:                                ZFREE(netport_kmsg_zone,kmsg);
        !          1112:                                break;
        !          1113:                }
        !          1114:        }
        !          1115: 
        !          1116: END
        !          1117: 
        !          1118: 
        !          1119: 
        !          1120: /*
        !          1121:  * np_tcp_conn_handler_close --
        !          1122:  *
        !          1123:  * Handler for one connection - closing phase.
        !          1124:  *
        !          1125:  * Parameters:
        !          1126:  *
        !          1127:  * cp: pointer to the connection record.
        !          1128:  *
        !          1129:  * Results:
        !          1130:  *
        !          1131:  * none.
        !          1132:  *
        !          1133:  * Note:
        !          1134:  *
        !          1135:  */
        !          1136: PRIVATE void np_tcp_conn_handler_close(cp)
        !          1137:        tcp_conn_ptr_t  cp;
        !          1138: BEGIN("np_tcp_conn_handler_close")
        !          1139:        tcp_trans_ptr_t         tp;
        !          1140:        int                     s;
        !          1141: 
        !          1142:        /*
        !          1143:         * Some transactions might be initiated after the active phase exits
        !          1144:         * and before this phase starts. Hopefully, they will be stopped by
        !          1145:         * the TCP_CLOSING or TCP_CLOSED states, or the send will fail.
        !          1146:         */
        !          1147:        mutex_lock(&conn_lock);
        !          1148:        mutex_lock(&cp->lock);
        !          1149:        mach_tcp_close(PORT_NULL,cp->sock);
        !          1150:        INCSTAT(tcp_close);
        !          1151:        if (cp->state == TCP_CLOSING) {
        !          1152:                conn_closing--;
        !          1153:        }
        !          1154:        cp->state = TCP_FREE;
        !          1155: 
        !          1156:        /*
        !          1157:         * Go down the list of waiting/pending transactions
        !          1158:         * and abort them.
        !          1159:         * The client is of course free to retry them later.
        !          1160:         */
        !          1161:        while (!queue_empty(&cp->trans)) {
        !          1162:                tp = (tcp_trans_ptr_t)queue_first(&cp->trans);
        !          1163:                DEBUG3(TCP_DBG_VERBOSE,0,2834,tp,tp->state,tp->client_id);
        !          1164:                if (tp->state == TCP_TR_WAITING) {
        !          1165:                        netport_handle_rp(tp->client_id,TR_SEND_FAILURE,0,0);
        !          1166:                } else {
        !          1167:                        netport_handle_rp(tp->client_id,TR_FAILURE,0,0);
        !          1168:                }
        !          1169:                queue_remove(&cp->trans,tp,tcp_trans_ptr_t,transq);
        !          1170:                ZFREE(tcp_trans_zone,tp);
        !          1171:        }
        !          1172:        queue_init(&cp->trans);
        !          1173:        cp->count = 0;
        !          1174:        queue_remove(&conn_lru,cp,tcp_conn_ptr_t,connq);
        !          1175:        queue_enter(&conn_free,cp,tcp_conn_ptr_t,connq);
        !          1176:        mutex_unlock(&cp->lock);
        !          1177:        conn_num--;
        !          1178:        DEBUG1(TCP_DBG_MAJOR,0,2835,conn_num);
        !          1179:        if (conn_num == (TCP_CONN_MAX - 1)) {
        !          1180:                /*
        !          1181:                 * OK to start accepting connections again.
        !          1182:                 */
        !          1183:                DEBUG0(TCP_DBG_MAJOR,0,2836);
        !          1184:                condition_signal(&conn_cond);
        !          1185:        }
        !          1186:        mutex_unlock(&conn_lock);
        !          1187: 
        !          1188:        RET;
        !          1189: END
        !          1190: 
        !          1191: 
        !          1192: 
        !          1193: /*
        !          1194:  * np_tcp_conn_handler --
        !          1195:  *
        !          1196:  * Handler for one connection.
        !          1197:  *
        !          1198:  * Parameters:
        !          1199:  *
        !          1200:  * Results:
        !          1201:  *
        !          1202:  *     Should never exit.
        !          1203:  *
        !          1204:  * Note:
        !          1205:  *
        !          1206:  * The first thing the thread must do is locate the connection record which
        !          1207:  * it is to service. This is guaranteed to succeed because there are exactly
        !          1208:  * as many threads as there are valid connection records.
        !          1209:  *
        !          1210:  * For clarity, this code is split into three different procedures handling
        !          1211:  * the opening, active and closing phases of the life of the connection.
        !          1212:  *
        !          1213:  */
        !          1214: PRIVATE void np_tcp_conn_handler()
        !          1215: BEGIN("np_tcp_conn_handler")
        !          1216:        tcp_conn_ptr_t  cp;
        !          1217:        int             i;
        !          1218:        boolean_t       active;
        !          1219: 
        !          1220:        /*
        !          1221:         * Find the connection record.
        !          1222:         */
        !          1223:        mutex_lock(&conn_lock);
        !          1224:        cp = NULL;
        !          1225:        for (i = 0; i < 32; i++) {
        !          1226:                if (conn_vec[i].state != TCP_INVALID) {
        !          1227:                        cp = &conn_vec[i];
        !          1228:                        if (cp->th == NULL) {
        !          1229:                                cp->th = current_thread();
        !          1230:                                break;
        !          1231:                        } else {
        !          1232:                                cp = NULL;
        !          1233:                        }
        !          1234:                }
        !          1235:        }
        !          1236:        mutex_unlock(&conn_lock);
        !          1237:        if (cp == NULL) {
        !          1238:                panic("TCP connection handler cannot find a connection record");
        !          1239:        }
        !          1240: 
        !          1241:        /*
        !          1242:         * Service loop.
        !          1243:         */
        !          1244:        for (;;) {
        !          1245:                /*
        !          1246:                 * First wait to be activated.
        !          1247:                 */
        !          1248:                mutex_lock(&cp->lock);
        !          1249:                while(cp->state == TCP_FREE) {
        !          1250:                        DEBUG0(TCP_DBG_VERBOSE,0,2811);
        !          1251:                        condition_wait(&cp->cond,&cp->lock);
        !          1252:                }
        !          1253: 
        !          1254:                /*
        !          1255:                 * At this point, the state is either TCP_OPENING (local open)
        !          1256:                 * or TCP_CONNECTED (remote open).
        !          1257:                 */
        !          1258:                DEBUG3(TCP_DBG_VERBOSE,0,2812,cp,cp->state,cp->dest);
        !          1259: 
        !          1260:                if (cp->state == TCP_OPENING) {
        !          1261:                        /*
        !          1262:                         * Open a new connection.
        !          1263:                         */
        !          1264:                        active = np_tcp_conn_handler_open(cp);
        !          1265:                } else {
        !          1266:                        active = TRUE;
        !          1267:                }
        !          1268:                cp->incarn = (cp->incarn++) & 0xff;
        !          1269:                mutex_unlock(&cp->lock);
        !          1270: 
        !          1271:                if (active) {
        !          1272:                        DEBUG3(TCP_DBG_MAJOR,0,2813,cp,cp->sock,cp->dest);
        !          1273:                        np_tcp_conn_handler_active(cp);
        !          1274:                        DEBUG3(TCP_DBG_MAJOR,0,2814,cp,cp->sock,cp->dest);
        !          1275:                }
        !          1276: 
        !          1277:                /*
        !          1278:                 * Close the connection.
        !          1279:                 */
        !          1280:                np_tcp_conn_handler_close(cp);
        !          1281:        }
        !          1282: END
        !          1283: 
        !          1284: 
        !          1285: 
        !          1286: /*
        !          1287:  * np_tcp_listener --
        !          1288:  *
        !          1289:  * Handler for the listener socket.
        !          1290:  *
        !          1291:  * Parameters:
        !          1292:  *
        !          1293:  * Results:
        !          1294:  *
        !          1295:  *     Should never exit.
        !          1296:  *
        !          1297:  * Note:
        !          1298:  *
        !          1299:  */
        !          1300: PRIVATE void np_tcp_listener()
        !          1301: BEGIN("np_tcp_listener")
        !          1302:        struct socket           *s;
        !          1303:        struct socket           *newsock;
        !          1304:        kern_return_t           ret;
        !          1305:        struct sockaddr_in      sname;
        !          1306:        int                     snamelen;
        !          1307:        tcp_conn_ptr_t          cp;
        !          1308: 
        !          1309:        /*
        !          1310:         * First create the listener socket.
        !          1311:         */
        !          1312:        mutex_lock(&conn_lock);
        !          1313:        ret = mach_tcp_socket(PORT_NULL,&s);
        !          1314:        mutex_unlock(&conn_lock);
        !          1315:        if (ret != KERN_SUCCESS) {
        !          1316:                ERROR((msg,"np_tcp_listener.socket failed: errno=%d",errno));
        !          1317:                panic("tcp");
        !          1318:        }
        !          1319:        sname.sin_family = AF_INET;
        !          1320:        sname.sin_port = htons(TCP_NETMSG_PORT);
        !          1321:        sname.sin_addr.s_addr = INADDR_ANY;
        !          1322:        ret = mach_tcp_bind(PORT_NULL,s,&sname,sizeof(struct sockaddr_in));
        !          1323:        if (ret != KERN_SUCCESS) {
        !          1324:                ERROR((msg,"np_tcp_listener.bind failed: errno=%d",errno));
        !          1325:                panic("tcp");
        !          1326:        }
        !          1327:        ret = mach_tcp_listen(PORT_NULL,s,2);
        !          1328:        if (ret != KERN_SUCCESS) {
        !          1329:                ERROR((msg,"np_tcp_listener.listen failed: errno=%d",errno));
        !          1330:                panic("tcp");
        !          1331:        }
        !          1332:        DEBUG1(TCP_DBG_VERBOSE,0,2806,s);
        !          1333: 
        !          1334:        /*
        !          1335:         * Loop forever accepting connections.
        !          1336:         */
        !          1337:        for (;;) {
        !          1338:                mutex_lock(&conn_lock);
        !          1339:                while (conn_num >= TCP_CONN_MAX) {
        !          1340:                        DEBUG1(TCP_DBG_VERBOSE,0,2810,conn_num);
        !          1341:                        condition_wait(&conn_cond,&conn_lock);
        !          1342:                }
        !          1343: 
        !          1344:                mutex_unlock(&conn_lock);
        !          1345:                DEBUG0(TCP_DBG_VERBOSE,0,2807);
        !          1346:                snamelen = sizeof(struct sockaddr_in);
        !          1347:                ret = mach_tcp_accept(PORT_NULL,s,&sname,&snamelen,&newsock);
        !          1348:                if (ret != KERN_SUCCESS) {
        !          1349:                        ERROR((msg,
        !          1350:                                "np_tcp_listener.accept failed: errno=%d",errno));
        !          1351:                        continue;
        !          1352:                }
        !          1353:                INCSTAT(tcp_accept);
        !          1354:                DEBUG0(TCP_DBG_VERBOSE,0,2808);
        !          1355: 
        !          1356:                if (np_flags & NP_SODEBUG) {
        !          1357:                        newsock->so_options |= SO_DEBUG;
        !          1358:                }
        !          1359: 
        !          1360:                mutex_lock(&conn_lock);
        !          1361:                if (queue_empty(&conn_free)) {
        !          1362:                        /*
        !          1363:                         * Initialize a new connection record.
        !          1364:                         */
        !          1365:                        cp = np_tcp_init_conn();
        !          1366:                } else {
        !          1367:                        cp = (tcp_conn_ptr_t)queue_first(&conn_free);
        !          1368:                        queue_remove(&conn_free,cp,tcp_conn_ptr_t,connq);
        !          1369:                }
        !          1370:                mutex_lock(&cp->lock);
        !          1371:                DEBUG4(TCP_DBG_MAJOR,0,2809,ret,cp,
        !          1372:                                        sname.sin_addr.s_addr,sname.sin_port);
        !          1373:                queue_enter_first(&conn_lru,cp,tcp_conn_ptr_t,connq);
        !          1374:                conn_num++;
        !          1375:                cp->sock = newsock;
        !          1376:                cp->dest = (netaddr_t)(sname.sin_addr.s_addr);
        !          1377:                cp->state = TCP_CONNECTED;
        !          1378:                cp->count = 0;
        !          1379: #ifdef notdef
        !          1380:                /*
        !          1381:                 * This is done when placing cp on the free list.
        !          1382:                 */
        !          1383:                queue_init(&cp->trans);
        !          1384: #endif notdef
        !          1385:                condition_signal(&cp->cond);
        !          1386:                mutex_unlock(&cp->lock);
        !          1387:                if ((conn_num - conn_closing) > TCP_CONN_STEADY) {
        !          1388:                        np_tcp_close_conn();
        !          1389:                }
        !          1390:                mutex_unlock(&conn_lock);
        !          1391:        }
        !          1392: 
        !          1393: END
        !          1394: 
        !          1395: 
        !          1396: 
        !          1397: /*
        !          1398:  * netport_tcp_init --
        !          1399:  *
        !          1400:  * Initialises the TCP transport protocol.
        !          1401:  *
        !          1402:  * Parameters:
        !          1403:  *
        !          1404:  * Results:
        !          1405:  *
        !          1406:  *     FALSE : we failed to initialise the TCP transport protocol.
        !          1407:  *     TRUE  : we were successful.
        !          1408:  *
        !          1409:  * Side effects:
        !          1410:  *
        !          1411:  *     Initialises the TCP protocol entry point in the switch array.
        !          1412:  *     Allocates the listener port and creates a thread to listen to the network.
        !          1413:  *
        !          1414:  */
        !          1415: EXPORT boolean_t netport_tcp_init()
        !          1416: BEGIN("netport_tcp_init")
        !          1417:        int             i;
        !          1418:        tcp_conn_ptr_t  cp;
        !          1419: 
        !          1420:        /*
        !          1421:         * Initialize the set of connection records and the lists.
        !          1422:         */
        !          1423:        for (i = 0; i < 32; i++) {
        !          1424:                conn_vec[i].state = TCP_INVALID;
        !          1425:                conn_vec[i].incarn = 0;
        !          1426:        }
        !          1427:        mutex_init(&conn_lock);
        !          1428:        mutex_lock(&conn_lock);
        !          1429:        condition_init(&conn_cond);
        !          1430:        queue_init(&conn_lru);
        !          1431:        queue_init(&conn_free);
        !          1432:        conn_num = 0;
        !          1433:        conn_closing = 0;
        !          1434:        trid_counter = 10;
        !          1435: 
        !          1436:        /*
        !          1437:         * Create a first connection record (just a test).
        !          1438:         */
        !          1439:        cp = np_tcp_init_conn();
        !          1440:        queue_enter(&conn_free,cp,tcp_conn_ptr_t,connq);
        !          1441: 
        !          1442:        /*
        !          1443:         * Set up the entry in the transport switch.
        !          1444:         */
        !          1445:        transport_switch[TR_TCP_ENTRY].sendrequest = netport_tcp_sendrequest;
        !          1446:        transport_switch[TR_TCP_ENTRY].sendreply = netport_tcp_sendreply;
        !          1447: 
        !          1448:        /*
        !          1449:         * Initialize the zone for transaction records.
        !          1450:         */
        !          1451:        tcp_trans_zone = zinit(sizeof(tcp_trans_t), 64 * 1024, page_size, FALSE, 
        !          1452:                                            "netport TCP transaction records");
        !          1453: 
        !          1454:        /*
        !          1455:         * Initialize the TCP interface.
        !          1456:         */
        !          1457:        mach_tcp_init(PORT_NULL,NULL);
        !          1458: 
        !          1459:        /*
        !          1460:         * Start the listener.
        !          1461:         */
        !          1462: #if    NeXT
        !          1463:        (void) kernel_thread(kernel_task,np_tcp_listener);
        !          1464: #else  NeX T
        !          1465:        (void) kernel_thread(first_task,np_tcp_listener);
        !          1466: #endif NeXT
        !          1467: 
        !          1468:        /*
        !          1469:         * Get the show on the road...
        !          1470:         */
        !          1471:        DEBUG0(TCP_DBG_MAJOR,0,2804);
        !          1472:        mutex_unlock(&conn_lock);
        !          1473:        RETURN(TRUE);
        !          1474: 
        !          1475: END
        !          1476: 
        !          1477: 
        !          1478: 
        !          1479: 
        !          1480: 

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.