|
|
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:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.