Whamcloud - gitweb
* Landed portals:b_port_step as follows...
[fs/lustre-release.git] / lnet / klnds / socklnd / socklnd_lib-darwin.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  * Copyright (C) 2002 Cluster File Systems, Inc.
5  * Author: Phil Schwan <phil@clusterfs.com>
6  *
7  * This file is part of Lustre, http://www.lustre.org.
8  *
9  * Lustre is free software; you can redistribute it and/or
10  * modify it under the terms of version 2 of the GNU General Public
11  * License as published by the Free Software Foundation.
12  *
13  * Lustre is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with Lustre; if not, write to the Free Software
20  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21  *
22  * Darwin porting library
23  * Make things easy to port
24  */
25 #include <mach/mach_types.h>
26 #include <string.h>
27 #include <netinet/in.h>
28 #include <netinet/tcp.h>
29 #include <sys/file.h>
30
31 #include "socknal.h"
32
33 #if 0
34 #undef SOCKNAL_SINGLE_FRAG_TX
35 #define SOCKNAL_SINGLE_FRAG_TX  1
36 #undef SOCKNAL_SINGLE_FRAG_RX
37 #define SOCKNAL_SINGLE_FRAG_RX  1
38 #endif
39
40 SYSCTL_DECL(_portals);
41
42 SYSCTL_NODE (_portals,           OID_AUTO,       ksocknal,        CTLFLAG_RW, 
43              0,                 "ksocknal_sysctl");
44
45 SYSCTL_INT(_portals_ksocknal,    OID_AUTO,       timeout, 
46            CTLTYPE_INT | CTLFLAG_RW ,           &ksocknal_tunables.ksnd_io_timeout, 
47            0,                                   "timeout");
48 SYSCTL_INT(_portals_ksocknal,    OID_AUTO,       eager_ack, 
49            CTLTYPE_INT | CTLFLAG_RW ,           &ksocknal_tunables.ksnd_eager_ack, 
50            0,                                   "eager_ack");
51 SYSCTL_INT(_portals_ksocknal,    OID_AUTO,       typed, 
52            CTLTYPE_INT | CTLFLAG_RW ,           &ksocknal_tunables.ksnd_typed_conns, 
53            0,                                   "typed");
54 SYSCTL_INT(_portals_ksocknal,    OID_AUTO,       min_bulk, 
55            CTLTYPE_INT | CTLFLAG_RW ,           &ksocknal_tunables.ksnd_min_bulk, 
56            0,                                   "min_bulk");
57 SYSCTL_INT(_portals_ksocknal,    OID_AUTO,       buffer_size, 
58            CTLTYPE_INT | CTLFLAG_RW ,           &ksocknal_tunables.ksnd_buffer_size, 
59            0,                                   "buffer_size");
60 SYSCTL_INT(_portals_ksocknal,    OID_AUTO,       nagle, 
61            CTLTYPE_INT | CTLFLAG_RW ,           &ksocknal_tunables.ksnd_nagle, 
62            0,                                   "nagle");
63
64 cfs_sysctl_table_t      ksocknal_top_ctl_table [] = {
65         &sysctl__portals_ksocknal,
66         &sysctl__portals_ksocknal_timeout,
67         &sysctl__portals_ksocknal_eager_ack,
68         &sysctl__portals_ksocknal_typed,
69         &sysctl__portals_ksocknal_min_bulk,
70         &sysctl__portals_ksocknal_buffer_size,
71         &sysctl__portals_ksocknal_nagle,
72         NULL
73 };
74
75 static unsigned long  ksocknal_mbuf_size = (u_quad_t)SB_MAX * MCLBYTES / (MSIZE + MCLBYTES);
76
77 struct socket *
78 sockfd_lookup(int fd, void *foo)
79 {
80         struct socket *so;
81         struct file *fp;
82         CFS_DECL_FUNNEL_DATA;
83
84         CFS_NET_IN;
85         getsock(current_proc()->p_fd, fd, &fp);
86         CFS_NET_EX;
87         so = (struct socket *)fp->f_data;
88         so->reserved4 = fp;
89         CFS_CONE_IN;
90         fref(fp);
91         CFS_CONE_EX;
92         return so;
93 }
94
95 extern struct fileops socketops;
96
97 static int
98 sock_map_fd (struct socket *so)
99 {
100         struct file *fp;
101         int fd;
102         CFS_DECL_FUNNEL_DATA;
103         
104         CFS_CONE_IN;
105         falloc(current_proc(), &fp, &fd);
106         fp->f_flag = FREAD|FWRITE;
107         fp->f_type = DTYPE_SOCKET;
108         fp->f_ops = &socketops;
109         fp->f_data = (caddr_t)so;
110         so->reserved4 = fp;
111         *fdflags(current_proc(), fd) &= ~UF_RESERVED;
112         CFS_CONE_EX;
113
114         return fd;
115 }
116
117 static void
118 sock_release(struct socket *so)
119 {
120         struct file *fp;
121         CFS_DECL_FUNNEL_DATA;
122
123         fp = (struct file *)so->reserved4;
124         so->reserved4 = NULL;
125         fp->f_data = NULL;
126         CFS_CONE_IN;
127         frele(fp);
128         CFS_CONE_EX;
129         CFS_NET_IN;
130         soshutdown(so, 0);
131         CFS_NET_EX;
132 }
133
134 static void
135 sock_fdrelse(int fd)
136
137         CFS_DECL_FUNNEL_DATA;
138
139         CFS_CONE_IN;
140         fdrelse(current_proc(), fd);
141         CFS_CONE_EX;
142 }
143
144 void
145 ksocknal_lib_bind_irq (unsigned int irq)
146 {
147         return;
148 }
149
150 unsigned int
151 ksocknal_lib_sock_irq (struct socket *sock)
152 {
153         return 0;
154 }
155
156 int
157 ksocknal_lib_get_conn_addrs (ksock_conn_t *conn)
158
159         struct sockaddr_in *sin; 
160         struct sockaddr    *sa; 
161         int                rc; 
162         CFS_DECL_NET_DATA;
163
164         CFS_NET_IN; 
165         rc = conn->ksnc_sock->so_proto->pr_usrreqs->pru_peeraddr(conn->ksnc_sock, &sa); 
166         LASSERT (!conn->ksnc_closing); 
167         if (rc != 0) { 
168                 CFS_NET_EX; 
169                 if (sa) FREE(sa, M_SONAME); 
170                 CERROR ("Error %d getting sock peer IP\n", rc); 
171                 return rc; 
172         } 
173         sin = (struct sockaddr_in *)sa; 
174         conn->ksnc_ipaddr = ntohl (sin->sin_addr.s_addr); 
175         conn->ksnc_port = ntohs (sin->sin_port); 
176         if (sa) FREE(sa, M_SONAME); 
177         rc = conn->ksnc_sock->so_proto->pr_usrreqs->pru_sockaddr(conn->ksnc_sock, &sa); 
178         CFS_NET_EX; 
179         if (rc != 0) { 
180                 if (sa) FREE(sa, M_SONAME); 
181                 CERROR ("Error %d getting sock local IP\n", rc); 
182                 return rc; 
183         } 
184         conn->ksnc_myipaddr = ntohl (sin->sin_addr.s_addr);
185
186         return 0;
187 }
188
189 int
190 ksocknal_lib_send_iov (ksock_conn_t *conn, ksock_tx_t *tx)
191
192 #if SOCKNAL_SINGLE_FRAG_TX 
193         struct iovec    scratch; 
194         struct iovec   *scratchiov = &scratch; 
195         int             niov = 1;
196 #else 
197         struct iovec   *scratchiov = conn->ksnc_tx_scratch_iov; 
198         int             niov = tx->tx_niov;
199 #endif
200         struct socket *sock = conn->ksnc_sock;
201         int            nob;
202         int            rc;
203         int            i;
204         struct uio  suio = {
205                 .uio_iov        = scratchiov,
206                 .uio_iovcnt     = niov,
207                 .uio_offset     = 0,
208                 .uio_resid      = 0,            /* This will be valued after a while */
209                 .uio_segflg     = UIO_SYSSPACE,
210                 .uio_rw         = UIO_WRITE,
211                 .uio_procp      = NULL
212         };
213         int  flags = MSG_DONTWAIT;
214         CFS_DECL_NET_DATA;
215
216         for (nob = i = 0; i < niov; i++) { 
217                 scratchiov[i] = tx->tx_iov[i]; 
218                 nob += scratchiov[i].iov_len; 
219         }
220         suio.uio_resid = nob;
221
222         CFS_NET_IN;
223         rc = sosend(sock, NULL, &suio, (struct mbuf *)0, (struct mbuf *)0, flags);
224         CFS_NET_EX; 
225
226         /* NB there is no return value can indicate how many 
227          * have been sent and how many resid, we have to get 
228          * sent bytes from suio. */
229         if (rc != 0) {
230                 if (suio.uio_resid != nob &&\
231                     (rc == ERESTART || rc == EINTR || rc == EWOULDBLOCK))
232                         /* We have sent something */
233                         rc = nob - suio.uio_resid;
234                 else if ( rc == EWOULDBLOCK ) 
235                         /* Actually, EAGAIN and EWOULDBLOCK have same value in OSX */
236                         rc = -EAGAIN;   
237                 else 
238                         rc = -rc;
239         } else  /* rc == 0 */
240                 rc = nob - suio.uio_resid;
241
242         return rc;
243 }
244
245 int
246 ksocknal_lib_send_kiov (ksock_conn_t *conn, ksock_tx_t *tx)
247 {
248 #if SOCKNAL_SINGLE_FRAG_TX || !SOCKNAL_RISK_KMAP_DEADLOCK 
249         struct iovec  scratch; 
250         struct iovec *scratchiov = &scratch; 
251         int           niov = 1;
252 #else
253         struct iovec *scratchiov = conn->ksnc_tx_scratch_iov; 
254         int           niov = tx->tx_nkiov;
255 #endif
256         struct socket *sock = conn->ksnc_sock;
257         ptl_kiov_t    *kiov = tx->tx_kiov;
258         int            nob;
259         int            rc;
260         int            i;
261         struct  uio suio = {
262                 .uio_iov        = scratchiov,
263                 .uio_iovcnt     = niov,
264                 .uio_offset     = 0, 
265                 .uio_resid      = 0,    /* It should be valued after a while */
266                 .uio_segflg     = UIO_SYSSPACE,
267                 .uio_rw         = UIO_WRITE,
268                 .uio_procp      = NULL
269         };
270         int  flags = MSG_DONTWAIT;
271         CFS_DECL_NET_DATA; 
272         
273         for (nob = i = 0; i < niov; i++) { 
274                 scratchiov[i].iov_base = cfs_kmap(kiov[i].kiov_page) + 
275                                          kiov[i].kiov_offset; 
276                 nob += scratchiov[i].iov_len = kiov[i].kiov_len; 
277         }
278         suio.uio_resid = nob;
279
280         CFS_NET_IN;
281         rc = sosend(sock, NULL, &suio, (struct mbuf *)0, (struct mbuf *)0, flags);
282         CFS_NET_EX;
283
284         for (i = 0; i < niov; i++) 
285                 cfs_kunmap(kiov[i].kiov_page);
286
287         if (rc != 0) {
288                 if (suio.uio_resid != nob &&\
289                     (rc == ERESTART || rc == EINTR || rc == EWOULDBLOCK))
290                         /* We have sent something */
291                         rc = nob - suio.uio_resid; 
292                 else if ( rc == EWOULDBLOCK ) 
293                         /* EAGAIN and EWOULD BLOCK have same value in OSX */
294                         rc = -EAGAIN;   
295                 else 
296                         rc = -rc;
297         } else  /* rc == 0 */
298                 rc = nob - suio.uio_resid;
299
300         return rc;
301 }
302
303 /*
304  * liang: Hack of inpcb and tcpcb.
305  * To get tcpcb of a socket, and call tcp_output
306  * to send quick ack.
307  */
308 struct ks_tseg_qent{
309         int foo;
310 };
311
312 struct ks_tcptemp{
313         int foo;
314 };
315
316 LIST_HEAD(ks_tsegqe_head, ks_tseg_qent);
317
318 struct ks_tcpcb {
319         struct ks_tsegqe_head t_segq;
320         int     t_dupacks;
321         struct ks_tcptemp *unused;
322         int    t_timer[4];
323         struct inpcb *t_inpcb;
324         int    t_state;
325         u_int  t_flags;
326         /*
327          * There are more fields but we dont need
328          * ......
329          */
330 };
331
332 #define TF_ACKNOW       0x00001
333 #define TF_DELACK       0x00002
334
335 struct ks_inpcb {
336         LIST_ENTRY(ks_inpcb) inp_hash;
337         struct  in_addr reserved1;
338         struct  in_addr reserved2;
339         u_short inp_fport;
340         u_short inp_lport;
341         LIST_ENTRY(inpcb) inp_list;
342         caddr_t inp_ppcb;
343         /*
344          * There are more fields but we dont need
345          * ......
346          */
347 };
348
349 #define ks_sotoinpcb(so)   ((struct ks_inpcb *)(so)->so_pcb)
350 #define ks_intotcpcb(ip)   ((struct ks_tcpcb *)(ip)->inp_ppcb)
351 #define ks_sototcpcb(so)   (intotcpcb(sotoinpcb(so)))
352
353 void
354 ksocknal_lib_eager_ack (ksock_conn_t *conn)
355 {
356         struct socket *sock = conn->ksnc_sock;
357         struct ks_inpcb  *inp = ks_sotoinpcb(sock);
358         struct ks_tcpcb  *tp = ks_intotcpcb(inp);
359         int s;
360         CFS_DECL_NET_DATA;
361
362         extern int tcp_output(register struct ks_tcpcb *tp);
363
364         CFS_NET_IN;
365         s = splnet();
366
367         if (tp && tp->t_flags & TF_DELACK){
368                 tp->t_flags &= ~TF_DELACK;
369                 tp->t_flags |= TF_ACKNOW;
370                 (void) tcp_output(tp);
371         }
372         splx(s);
373
374         /*
375          * No TCP_QUICKACK supported in BSD, so I have to call tcp_fasttimo
376          * to send immediate ACK. It's not the best resolution because
377          * tcp_fasttimo will send out ACK for all delayed-ack tcp socket.
378          * Anyway, it's working now. 
379          * extern void tcp_fasttimo(); 
380          * tcp_fasttimo();
381          */
382         CFS_NET_EX;
383
384         return;
385 }
386
387 int
388 ksocknal_lib_recv_iov (ksock_conn_t *conn)
389 {
390 #if SOCKNAL_SINGLE_FRAG_RX 
391         struct iovec  scratch; 
392         struct iovec *scratchiov = &scratch; 
393         int           niov = 1;
394 #else 
395         struct iovec *scratchiov = conn->ksnc_rx_scratch_iov; 
396         int           niov = conn->ksnc_rx_niov;
397 #endif
398         struct iovec *iov = conn->ksnc_rx_iov;
399         int          nob;
400         int          rc;
401         int          i;
402         struct uio  ruio = {
403                 .uio_iov        = scratchiov,
404                 .uio_iovcnt     = niov,
405                 .uio_offset     = 0,
406                 .uio_resid      = 0,    /* It should be valued after a while */
407                 .uio_segflg     = UIO_SYSSPACE,
408                 .uio_rw         = UIO_READ,
409                 .uio_procp      = NULL
410         };
411         int         flags = MSG_DONTWAIT;
412         CFS_DECL_NET_DATA;
413
414         for (nob = i = 0; i < niov; i++) { 
415                 scratchiov[i] = iov[i]; 
416                 nob += scratchiov[i].iov_len; 
417         } 
418         LASSERT (nob <= conn->ksnc_rx_nob_wanted);
419
420         ruio.uio_resid = nob;
421
422         CFS_NET_IN;
423         rc = soreceive(conn->ksnc_sock, (struct sockaddr **)0, &ruio, (struct mbuf **)0, (struct mbuf **)0, &flags);
424         CFS_NET_EX;
425         if (rc){
426                 if (ruio.uio_resid != nob && \
427                     (rc == ERESTART || rc == EINTR || rc == EWOULDBLOCK || rc == EAGAIN))
428                         /* data particially received */
429                         rc = nob - ruio.uio_resid; 
430                 else if (rc == EWOULDBLOCK) 
431                         /* EAGAIN and EWOULD BLOCK have same value in OSX */
432                         rc = -EAGAIN; 
433                 else
434                         rc = -rc;
435         } else 
436                 rc = nob - ruio.uio_resid;
437
438         return (rc);
439 }
440
441 int
442 ksocknal_lib_recv_kiov (ksock_conn_t *conn)
443 {
444 #if SOCKNAL_SINGLE_FRAG_RX || !SOCKNAL_RISK_KMAP_DEADLOCK 
445         struct iovec  scratch; 
446         struct iovec *scratchiov = &scratch; 
447         int           niov = 1;
448 #else 
449         struct iovec *scratchiov = conn->ksnc_rx_scratch_iov; 
450         int           niov = conn->ksnc_rx_nkiov;
451 #endif
452         ptl_kiov_t    *kiov = conn->ksnc_rx_kiov;
453         int           nob;
454         int           rc;
455         int           i;
456         struct uio  ruio = {
457                 .uio_iov        = scratchiov,
458                 .uio_iovcnt     = niov,
459                 .uio_offset     = 0,
460                 .uio_resid      = 0,
461                 .uio_segflg     = UIO_SYSSPACE,
462                 .uio_rw         = UIO_READ,
463                 .uio_procp      = NULL
464         };
465         int         flags = MSG_DONTWAIT;
466         CFS_DECL_NET_DATA;
467
468         for (nob = i = 0; i < niov; i++) { 
469                 scratchiov[i].iov_base = cfs_kmap(kiov[i].kiov_page) + kiov[i].kiov_offset; 
470                 nob += scratchiov[i].iov_len = kiov[i].kiov_len; 
471         } 
472         LASSERT (nob <= conn->ksnc_rx_nob_wanted);
473
474         ruio.uio_resid = nob;
475
476         CFS_NET_IN;
477         rc = soreceive(conn->ksnc_sock, (struct sockaddr **)0, &ruio, (struct mbuf **)0, NULL, &flags);
478         CFS_NET_EX;
479
480         for (i = 0; i < niov; i++) 
481                 cfs_kunmap(kiov[i].kiov_page);
482
483         if (rc){
484                 if (ruio.uio_resid != nob && \
485                     (rc == ERESTART || rc == EINTR || rc == EWOULDBLOCK))
486                         /* data particially received */
487                         rc = nob - ruio.uio_resid; 
488                 else if (rc == EWOULDBLOCK)
489                         /* receive blocked, EWOULDBLOCK == EAGAIN */ 
490                         rc = -EAGAIN; 
491                 else
492                         rc = -rc;
493         } else
494                 rc = nob - ruio.uio_resid;
495
496         return (rc);
497 }
498
499 int
500 ksocknal_lib_sock_write (struct socket *sock, void *buffer, int nob)
501 {
502         int           rc;
503         CFS_DECL_NET_DATA;
504
505         while (nob > 0) {
506                 struct iovec  iov = {
507                         .iov_base = buffer,
508                         .iov_len  = nob
509                 };
510                 struct  uio suio = {
511                         .uio_iov        = &iov,
512                         .uio_iovcnt     = 1,
513                         .uio_offset     = 0,
514                         .uio_resid      = nob,
515                         .uio_segflg     = UIO_SYSSPACE,
516                         .uio_rw         = UIO_WRITE,
517                         .uio_procp      = NULL
518                 };
519
520                 CFS_NET_IN;
521                 rc = sosend(sock, NULL, &suio, (struct mbuf *)0, (struct mbuf *)0, 0);
522                 CFS_NET_EX;
523
524                 if (rc != 0) {
525                         if ( suio.uio_resid != nob && ( rc == ERESTART || rc == EINTR ||\
526                                                 rc == EWOULDBLOCK))
527                                 rc = 0;
528                         if ( rc != 0 )
529                                 return -rc;
530                         rc = nob - suio.uio_resid;
531                         buffer = ((char *)buffer) + rc;
532                         nob = suio.uio_resid;
533                         continue;
534                 }
535                 break;
536         }
537
538         return (0);
539 }
540
541 int
542 ksocknal_lib_sock_read (struct socket *sock, void *buffer, int nob)
543 {
544         int           rc;
545         CFS_DECL_NET_DATA;
546
547         while (nob > 0) {
548                 struct iovec  iov = {
549                         .iov_base = buffer,
550                         .iov_len  = nob
551                 };
552                 struct uio  ruio = {
553                         .uio_iov        = &iov,
554                         .uio_iovcnt     = 1,
555                         .uio_offset     = 0,
556                         .uio_resid      = nob,
557                         .uio_segflg     = UIO_SYSSPACE,
558                         .uio_rw         = UIO_READ,
559                         .uio_procp      = NULL
560                 };
561
562                 CFS_NET_IN;
563                 rc = soreceive(sock, (struct sockaddr **)0, &ruio, (struct mbuf **)0, (struct mbuf **)0, (int *)0);
564                 CFS_NET_EX;
565
566                 if (rc != 0) {
567                         if ( ruio.uio_resid != nob && ( rc == ERESTART || rc == EINTR ||\
568                                                 rc == EWOULDBLOCK))
569                                 rc = 0;
570                         if (rc != 0)
571                                 return -rc;
572                         rc = nob - ruio.uio_resid;
573                         buffer = ((char *)buffer) + rc;
574                         nob = ruio.uio_resid;
575                         continue;
576                 }
577                 break;
578         }
579
580         return (0);
581 }
582
583 int
584 ksocknal_lib_get_conn_tunables (ksock_conn_t *conn, int *txmem, int *rxmem, int *nagle)
585 {
586         struct sockopt  sopt;
587         struct socket *sock = conn->ksnc_sock;
588         int            len;
589         int            rc;
590         CFS_DECL_NET_DATA;
591
592         rc = ksocknal_getconnsock (conn);
593         if (rc != 0) {
594                 LASSERT (conn->ksnc_closing);
595                 *txmem = *rxmem = *nagle = 0;
596                 rc = -ESHUTDOWN;
597                 goto out;
598         }
599         len = sizeof(*txmem);
600         bzero(&sopt, sizeof sopt);
601         sopt.sopt_dir = SOPT_GET; 
602         sopt.sopt_level = SOL_SOCKET; 
603         sopt.sopt_name = SO_SNDBUF; 
604         sopt.sopt_val = txmem; 
605         sopt.sopt_valsize = len;
606
607         CFS_NET_IN;
608         rc = sogetopt(sock, &sopt);
609         if (rc == 0) {
610                 len = sizeof(*rxmem);
611                 sopt.sopt_name = SO_RCVBUF;
612                 sopt.sopt_val = rxmem;
613                 rc = sogetopt(sock, &sopt);
614         }
615         if (rc == 0) {
616                 len = sizeof(*nagle);
617                 sopt.sopt_level = IPPROTO_TCP;
618                 sopt.sopt_name = TCP_NODELAY;
619                 sopt.sopt_val = nagle;
620                 rc = sogetopt(sock, &sopt);
621         }
622         CFS_NET_EX;
623
624         ksocknal_putconnsock (conn);
625
626         if (rc == 0)
627                 *nagle = !*nagle;
628         else
629                 *txmem = *rxmem = *nagle = 0;
630 out:
631         return (-rc);
632 }
633
634 int
635 ksocknal_lib_setup_sock (struct socket *so)
636 {
637         struct sockopt  sopt;
638         int             rc; 
639         int             option; 
640         int             keep_idle; 
641         int             keep_intvl; 
642         int             keep_count; 
643         int             do_keepalive; 
644         struct linger   linger;
645         CFS_DECL_NET_DATA;
646
647         /* Ensure this socket aborts active sends immediately when we close
648          * it. */
649
650         bzero(&sopt, sizeof sopt);
651
652         linger.l_onoff = 0;
653         linger.l_linger = 0;
654         sopt.sopt_dir = SOPT_SET;
655         sopt.sopt_level = SOL_SOCKET;
656         sopt.sopt_name = SO_LINGER;
657         sopt.sopt_val = &linger;
658         sopt.sopt_valsize = sizeof(linger);
659
660         CFS_NET_IN;
661         rc = sosetopt(so, &sopt);
662         if (rc != 0) {
663                 CERROR ("Can't set SO_LINGER: %d\n", rc);
664                 goto out;
665         }
666
667
668         if (!ksocknal_tunables.ksnd_nagle) { 
669                 option = 1; 
670                 bzero(&sopt, sizeof sopt);
671                 sopt.sopt_dir = SOPT_SET; 
672                 sopt.sopt_level = IPPROTO_TCP;
673                 sopt.sopt_name = TCP_NODELAY; 
674                 sopt.sopt_val = &option; 
675                 sopt.sopt_valsize = sizeof(option);
676                 rc = sosetopt(so, &sopt);
677                 if (rc != 0) { 
678                         CERROR ("Can't disable nagle: %d\n", rc); 
679                         goto out;
680                 } 
681         } 
682         if (ksocknal_tunables.ksnd_buffer_size > 0) { 
683                 option = ksocknal_tunables.ksnd_buffer_size; 
684                 if (option > ksocknal_mbuf_size) 
685                         option = ksocknal_mbuf_size; 
686                                                 
687                 sopt.sopt_dir = SOPT_SET; 
688                 sopt.sopt_level = SOL_SOCKET; 
689                 sopt.sopt_name = SO_SNDBUF; 
690                 sopt.sopt_val = &option; 
691                 sopt.sopt_valsize = sizeof(option); 
692                 rc = sosetopt(so, &sopt); 
693                 if (rc != 0) { 
694                         CERROR ("Can't set send buffer %d: %d\n", 
695                                         option, rc); 
696                         goto out;
697                 } 
698                 
699                 sopt.sopt_name = SO_RCVBUF; 
700                 rc = sosetopt(so, &sopt); 
701                 if (rc != 0) { 
702                         CERROR ("Can't set receive buffer %d: %d\n", 
703                                         option, rc); 
704                         goto out;
705                 }
706         } 
707         /* snapshot tunables */ 
708         keep_idle  = ksocknal_tunables.ksnd_keepalive_idle; 
709         keep_count = ksocknal_tunables.ksnd_keepalive_count; 
710         keep_intvl = ksocknal_tunables.ksnd_keepalive_intvl;
711
712         do_keepalive = (keep_idle > 0 && keep_count > 0 && keep_intvl > 0); 
713         option = (do_keepalive ? 1 : 0); 
714         bzero(&sopt, sizeof sopt); 
715         sopt.sopt_dir = SOPT_SET; 
716         sopt.sopt_level = SOL_SOCKET; 
717         sopt.sopt_name = SO_KEEPALIVE; 
718         sopt.sopt_val = &option; 
719         sopt.sopt_valsize = sizeof(option); 
720         rc = sosetopt(so, &sopt); 
721         if (rc != 0) { 
722                 CERROR ("Can't set SO_KEEPALIVE: %d\n", rc); 
723                 goto out; 
724         }
725         
726         if (!do_keepalive) { 
727                 /* no more setting, just return */
728                 rc = 0;
729                 goto out;
730         } 
731         
732         bzero(&sopt, sizeof sopt); 
733         sopt.sopt_dir = SOPT_SET; 
734         sopt.sopt_level = IPPROTO_TCP; 
735         sopt.sopt_name = TCP_KEEPALIVE; 
736         sopt.sopt_val = &keep_idle; 
737         sopt.sopt_valsize = sizeof(keep_idle); 
738         rc = sosetopt(so, &sopt); 
739         if (rc != 0) { 
740                 CERROR ("Can't set TCP_KEEPALIVE : %d\n", rc); 
741                 goto out; 
742         }
743 out:
744         CFS_NET_EX;
745         return (-rc);
746 }
747
748 int
749 ksocknal_lib_connect_sock (struct socket **sockp, int *may_retry, 
750                            ksock_route_t *route, int local_port)
751 {
752         struct sockaddr_in  locaddr;
753         struct sockaddr_in  srvaddr;
754         struct timeval      tv;
755         int                 fd;
756         struct socket      *so;
757         struct sockopt      sopt;
758         int                 option;
759         int                 rc;
760         int                 s;
761         CFS_DECL_FUNNEL_DATA;
762
763         ENTRY; 
764         bzero (&locaddr, sizeof (locaddr)); 
765         locaddr.sin_len = sizeof(struct sockaddr_in); 
766         locaddr.sin_family = AF_INET; 
767         locaddr.sin_port = htons (local_port);
768         locaddr.sin_addr.s_addr = 
769                 (route->ksnr_myipaddr != 0) ? htonl(route->ksnr_myipaddr)
770                                             : INADDR_ANY;
771         bzero(&srvaddr, sizeof(srvaddr));
772         srvaddr.sin_len = sizeof(struct sockaddr_in);
773         srvaddr.sin_family = AF_INET;
774         srvaddr.sin_port = htons (route->ksnr_port);
775         srvaddr.sin_addr.s_addr = htonl (route->ksnr_ipaddr);
776
777         *may_retry = 0;
778
779         CFS_NET_IN;
780         rc = socreate(PF_INET, &so, SOCK_STREAM, 0); 
781         CFS_NET_EX;
782         *sockp = so;
783         if (rc != 0) {
784                 CERROR ("Can't create autoconnect socket: %d\n", rc);
785                 return (-rc);
786         }
787
788         /*
789          * XXX
790          * Liang: what do we need here? 
791          */
792         fd = sock_map_fd (so);
793         if (fd < 0) {
794                 sock_release (so);
795                 CERROR ("sock_map_fd error %d\n", fd);
796                 return (fd);
797         }
798         sock_fdrelse(fd);
799
800         /* Set the socket timeouts, so our connection attempt completes in
801          * finite time */
802         tv.tv_sec = ksocknal_tunables.ksnd_io_timeout;
803         tv.tv_usec = 0;
804         bzero(&sopt, sizeof sopt);
805         sopt.sopt_dir = SOPT_SET;
806         sopt.sopt_level = SOL_SOCKET;
807         sopt.sopt_name = SO_SNDTIMEO;
808         sopt.sopt_val = &tv;
809         sopt.sopt_valsize = sizeof(tv);
810
811         CFS_NET_IN;
812         rc = sosetopt(so, &sopt);
813         if (rc != 0) { 
814                 CFS_NET_EX;
815                 CERROR ("Can't set send timeout %d: %d\n",
816                         ksocknal_tunables.ksnd_io_timeout, rc);
817                 goto out;
818         }
819         sopt.sopt_level = SOL_SOCKET;
820         sopt.sopt_name = SO_RCVTIMEO;
821         rc = sosetopt(so, &sopt);
822         if (rc != 0) {
823                 CFS_NET_EX;
824                 CERROR ("Can't set receive timeout %d: %d\n",
825                         ksocknal_tunables.ksnd_io_timeout, rc);
826                 goto out;
827         } 
828         option = 1;
829         sopt.sopt_level = SOL_SOCKET;
830         sopt.sopt_name = SO_REUSEADDR;
831         sopt.sopt_val = &option;
832         sopt.sopt_valsize = sizeof(option);
833         rc = sosetopt(so, &sopt);
834         if (rc != 0) {
835                 CFS_NET_EX;
836                 CERROR ("Can't set sock reuse address: %d\n", rc);
837                 goto out;
838         } 
839         rc = sobind(so, (struct sockaddr *)&locaddr); 
840         if (rc == EADDRINUSE) { 
841                 CFS_NET_EX; 
842                 CDEBUG(D_NET, "Port %d already in use\n", local_port); 
843                 *may_retry = 1; 
844                 goto out;
845         }
846         if (rc != 0) { 
847                 CFS_NET_EX; 
848                 CERROR ("Can't bind to local IP Address %u.%u.%u.%u: %d\n", 
849                         HIPQUAD(route->ksnr_myipaddr), rc); 
850                 goto out; 
851         }
852         rc = soconnect(so, (struct sockaddr *)&srvaddr);
853         *may_retry = (rc == EADDRNOTAVAIL || rc == EADDRINUSE);
854         if (rc != 0) { 
855                 CFS_NET_EX;
856                 if (rc != EADDRNOTAVAIL && rc != EADDRINUSE)
857                         CERROR ("Can't connect to nid "LPX64 
858                                 " local IP: %u.%u.%u.%u," 
859                                 " remote IP: %u.%u.%u.%u/%d: %d\n", 
860                                 route->ksnr_peer->ksnp_nid, 
861                                 HIPQUAD(route->ksnr_myipaddr), 
862                                 HIPQUAD(route->ksnr_ipaddr), 
863                                 route->ksnr_port, rc); 
864                 goto out;
865         }
866
867         s = splnet();
868         while ((so->so_state & SS_ISCONNECTING) && so->so_error == 0) {
869                 CDEBUG(D_NET, "ksocknal sleep for waiting auto_connect.\n");
870                 (void) tsleep((caddr_t)&so->so_timeo, PSOCK, "ksocknal_conn", hz);
871         }
872         LASSERT((so->so_state & SS_ISCONNECTED));
873         splx(s);
874         CFS_NET_EX;
875
876         rc = so->so_error; 
877         if (rc != 0) { 
878                 CERROR ("Error %d waiting for connection to nid "LPX64 
879                         " local IP: %u.%u.%u.%u," 
880                         " remote IP: %u.%u.%u.%u/%d: %d\n", rc,
881                         route->ksnr_peer->ksnp_nid, 
882                         HIPQUAD(route->ksnr_myipaddr), 
883                         HIPQUAD(route->ksnr_ipaddr), 
884                         route->ksnr_port, rc); 
885                 goto out; 
886         }
887         return (-rc);
888
889  out:
890         rele_file(KSN_SOCK2FILE(so));
891
892         return (-rc);
893 }
894
895 void
896 ksocknal_lib_push_conn(ksock_conn_t *conn)
897
898         struct socket   *sock; 
899         struct sockopt  sopt; 
900         int             val = 1; 
901         int             rc; 
902         CFS_DECL_NET_DATA; 
903         
904         rc = ksocknal_getconnsock (conn); 
905         if (rc != 0)            /* being shut down */ 
906                 return; 
907         sock = conn->ksnc_sock; 
908         bzero(&sopt, sizeof sopt); 
909         sopt.sopt_dir = SOPT_SET; 
910         sopt.sopt_level = IPPROTO_TCP; 
911         sopt.sopt_name = TCP_NODELAY; 
912         sopt.sopt_val = &val; 
913         sopt.sopt_valsize = sizeof val; 
914
915         CFS_NET_IN; 
916         sosetopt(sock, &sopt); 
917         CFS_NET_EX; 
918
919         ksocknal_putconnsock (conn);
920         return;
921 }
922
923 extern void ksocknal_read_callback (ksock_conn_t *conn);
924 extern void ksocknal_write_callback (ksock_conn_t *conn);
925
926 static void
927 ksocknal_upcall(struct socket *so, caddr_t arg, int waitf)
928 {
929         ksock_conn_t  *conn;
930         CFS_DECL_NET_DATA;
931         ENTRY;
932
933         read_lock (&ksocknal_data.ksnd_global_lock);
934         conn = so->reserved3;
935
936         if (conn == NULL){
937                 /* More processing is needed?  */
938                 goto out;
939         }
940         if ((so->so_rcv.sb_flags & SB_UPCALL) || !arg ) {
941                 extern int soreadable(struct socket *so);
942                 CFS_NET_IN;
943                 if (conn->ksnc_rx_nob_wanted && soreadable(so)){
944                         /* To verify whether the upcall is for receive */
945                         CFS_NET_EX;
946                         ksocknal_read_callback (conn);
947                 }else
948                         CFS_NET_EX;
949         }
950         /* go foward? */
951         if ((so->so_snd.sb_flags & SB_UPCALL) || !arg){
952                 extern int sowriteable(struct socket *so);
953                 CFS_NET_IN;
954                 if (sowriteable(so)){
955                         /* socket is writable */
956                         CFS_NET_EX;
957                         ksocknal_write_callback(conn);
958                 } else 
959                         CFS_NET_EX;
960         }
961 out:
962         read_unlock (&ksocknal_data.ksnd_global_lock);
963
964         EXIT;
965 }
966
967 void
968 ksocknal_lib_save_callback(struct socket *sock, ksock_conn_t *conn)
969
970         /* No callback need to save in osx */
971         return;
972 }
973
974 void
975 ksocknal_lib_set_callback(struct socket *sock, ksock_conn_t *conn)
976
977         CFS_DECL_NET_DATA;
978
979         CFS_NET_IN;
980         sock->so_upcallarg = (void *)sock;  /* anything not NULL */ 
981         sock->so_upcall = ksocknal_upcall; 
982         sock->so_snd.sb_timeo = 0; 
983         sock->so_rcv.sb_timeo = 2 * HZ; 
984         sock->so_rcv.sb_flags |= SB_UPCALL; 
985         sock->so_snd.sb_flags |= SB_UPCALL; 
986         sock->reserved3 = conn;
987         CFS_NET_EX;
988         return;
989 }
990
991 void
992 ksocknal_lib_act_callback(struct socket *sock)
993 {
994         /* upcall will take the network funnel */
995         ksocknal_upcall (sock, 0, 0);
996 }
997
998 void 
999 ksocknal_lib_reset_callback(struct socket *sock, ksock_conn_t *conn)
1000
1001         CFS_DECL_NET_DATA;
1002
1003         CFS_NET_IN;
1004         sock->so_upcall = NULL; 
1005         sock->so_upcallarg = NULL; 
1006         sock->so_rcv.sb_flags &= ~SB_UPCALL; 
1007         sock->so_snd.sb_flags &= ~SB_UPCALL;
1008         CFS_NET_EX;
1009 }
1010
1011