|
|
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.