Back to index

lightning-sunbird  0.9+nobinonly
macos-ip.c
Go to the documentation of this file.
00001 /* ***** BEGIN LICENSE BLOCK *****
00002  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00003  *
00004  * The contents of this file are subject to the Mozilla Public License Version
00005  * 1.1 (the "License"); you may not use this file except in compliance with
00006  * the License. You may obtain a copy of the License at
00007  * http://www.mozilla.org/MPL/
00008  *
00009  * Software distributed under the License is distributed on an "AS IS" basis,
00010  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00011  * for the specific language governing rights and limitations under the
00012  * License.
00013  *
00014  * The Original Code is Mozilla Communicator client code, released
00015  * March 31, 1998.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998-1999
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either the GNU General Public License Version 2 or later (the "GPL"), or
00026  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 /*
00038  *  Copyright (c) 1995 Regents of the University of Michigan.
00039  *  All rights reserved.
00040  */
00041 /*
00042  *  macos-ip.c -- Macintosh platform-specific TCP & UDP related code
00043  */
00044 
00045 #ifndef lint 
00046 static char copyright[] = "@(#) Copyright (c) 1995 Regents of the University of Michigan.\nAll rights reserved.\n";
00047 #endif
00048 
00049 #include <stdio.h>
00050 #include <string.h>
00051 #include <stdlib.h>
00052 #include <Memory.h>
00053 #include "ldap-int.h"
00054 
00055 
00056 int
00057 nsldapi_connect_to_host( LDAP *ld, Sockbuf *sb, char *host, unsigned long address,
00058        int port, int async, int secure )
00059 /*
00060  * if host == NULL, connect using address
00061  * "address" and "port" must be in network byte order
00062  * zero is returned upon success, -1 if fatal error, -2 EINPROGRESS
00063  * if -1 is returned, ld_errno is set
00064  * async is only used ifndef NO_REFERRALS (non-0 means don't wait for connect)
00065  * XXX async is not used yet!
00066  */
00067 {
00068        void                 *tcps;
00069        short                i;
00070        int                         err;
00071     InetHostInfo     hi;
00072 
00073        LDAPDebug( LDAP_DEBUG_TRACE, "connect_to_host: %s:%d\n",
00074            ( host == NULL ) ? "(by address)" : host, ntohs( port ), 0 );
00075 
00076        /* Initialize OpenTransport, or find out from the host app whether it is installed */
00077        (void)tcp_init();
00078        
00079        if ( host != NULL && gethostinfobyname( host, &hi ) != noErr ) {
00080               LDAP_SET_LDERRNO( ld, LDAP_CONNECT_ERROR, NULL, NULL );
00081               return( -1 );
00082        }
00083 
00084        if ( ld->ld_socket_fn == NULL ) {
00085               tcps = tcpopen( NULL, TCP_BUFSIZ );
00086        } else {
00087               tcps = ld->ld_socket_fn( AF_INET, SOCK_STREAM, 0 );
00088        }
00089 
00090        if ( tcps == NULL ) {
00091               LDAP_SET_LDERRNO( ld, LDAP_LOCAL_ERROR, NULL, NULL );
00092               return( -1 );
00093        }
00094 
00095        if ( secure && ld->ld_ssl_enable_fn( tcps ) < 0 ) {
00096               if ( ld->ld_close_fn == NULL ) {
00097                      tcpclose( (tcpstream *)tcps );
00098               } else {
00099                      ld->ld_close_fn( tcps );
00100               }
00101               LDAP_SET_LDERRNO( ld, LDAP_LOCAL_ERROR, NULL, NULL );
00102               return( -1 );
00103        }
00104 
00105     for ( i = 0; host == NULL || hi.addrs[ i ] != 0; ++i ) {
00106        if ( host != NULL ) {
00107                      SAFEMEMCPY( (char *)&address, (char *)&hi.addrs[ i ], sizeof( long ));
00108               }
00109 
00110 
00111               if ( ld->ld_connect_fn == NULL ) {
00112                      if ( tcpconnect( tcps, address, port ) == 0 ) {
00113                             err = -1;
00114                      } else {
00115                             err = 0;
00116                      }
00117               } else {
00118                      struct sockaddr_in   sin;
00119                      (void)memset( (char *)&sin, 0, sizeof( struct sockaddr_in ));
00120                      sin.sin_family = AF_INET;
00121                      sin.sin_port = port;
00122                      sin.sin_addr.s_addr = address;
00123 
00124                      err = ld->ld_connect_fn( tcps, (struct sockaddr *)&sin,
00125                             sizeof( struct sockaddr_in ));
00126               }
00127 
00128               if ( err == 0 ) {
00129                      sb->sb_sd = (void *)tcps;
00130                      return( 0 );
00131               }
00132 
00133               if ( host == NULL ) {       /* using single address -- not hi.addrs array */
00134                      break;
00135               }
00136        }
00137        
00138        LDAPDebug( LDAP_DEBUG_TRACE, "tcpconnect failed\n", 0, 0, 0 );
00139        LDAP_SET_LDERRNO( ld, LDAP_CONNECT_ERROR, NULL, NULL );
00140        LDAP_SET_ERRNO( ld, EHOSTUNREACH );  /* close enough */
00141 
00142        if ( ld->ld_close_fn == NULL ) {
00143               tcpclose( (tcpstream *)tcps );
00144        } else {
00145               ld->ld_close_fn( tcps );
00146        }
00147        return( -1 );
00148 }
00149 
00150 
00151 void
00152 nsldapi_close_connection( LDAP *ld, Sockbuf *sb )
00153 {
00154        if ( ld->ld_close_fn == NULL ) {
00155               tcpclose( (tcpstream *)sb->sb_sd );
00156        } else {
00157               ld->ld_close_fn( sb->sb_sd );
00158        }
00159 }
00160 
00161 
00162 #ifdef KERBEROS
00163 char *
00164 host_connected_to( Sockbuf *sb )
00165 {
00166        ip_addr addr;
00167        
00168     InetHostInfo     hi;
00169 
00170        if ( tcpgetpeername( (tcpstream *)sb->sb_sd, &addr, NULL ) != noErr ) {
00171               return( NULL );
00172        }
00173 
00174        if ( gethostinfobyaddr( addr, &hi ) == noErr ) {
00175               return( strdup( hi.name ));
00176        }
00177 
00178        return( NULL );
00179 }
00180 #endif /* KERBEROS */
00181 
00182 
00183 struct tcpstreaminfo {
00184        struct tcpstream     *tcpsi_stream;
00185        Boolean                            tcpsi_check_read;
00186        Boolean                            tcpsi_is_read_ready;
00187        Boolean                            tcpsi_check_write;
00188        Boolean                            tcpsi_is_write_ready;
00189 };
00190 
00191 /* for BSD-compatible I/O functions */
00192 struct stdselectinfo {
00193        fd_set ssi_readfds;
00194        fd_set ssi_writefds;
00195        fd_set ssi_use_readfds;
00196        fd_set ssi_use_writefds;
00197 };
00198 
00199 struct selectinfo {
00200        short                              si_count;
00201        struct tcpstreaminfo *si_streaminfo;
00202        struct stdselectinfo si_stdinfo;
00203 };
00204 
00205 
00206 void
00207 nsldapi_mark_select_write( LDAP *ld, Sockbuf *sb )
00208 {
00209        struct selectinfo    *sip;
00210        struct tcpstreaminfo *tcpsip;
00211        short                i;
00212 
00213        LDAPDebug( LDAP_DEBUG_TRACE, "mark_select_write: stream %x\n",
00214            (tcpstream *)sb->sb_sd, 0, 0 );
00215 
00216        if (( sip = (struct selectinfo *)ld->ld_selectinfo ) == NULL ) {
00217               return;
00218        }
00219 
00220        if ( ld->ld_select_fn != NULL ) {
00221               if ( !FD_ISSET( (int)sb->sb_sd, &sip->si_stdinfo.ssi_writefds )) {
00222                   FD_SET( (int)sb->sb_sd, &sip->si_stdinfo.ssi_writefds );
00223               }
00224               return;
00225        }
00226 
00227        for ( i = 0; i < sip->si_count; ++i ) {    /* make sure stream is not already in the list... */
00228               if ( sip->si_streaminfo[ i ].tcpsi_stream == (tcpstream *)sb->sb_sd) {
00229                      sip->si_streaminfo[ i ].tcpsi_check_write = true;
00230                      sip->si_streaminfo[ i ].tcpsi_is_write_ready = false;
00231                      return;
00232               }
00233        }
00234 
00235        /* add a new stream element to our array... */
00236        if ( sip->si_count <= 0 ) {
00237               tcpsip = (struct tcpstreaminfo *)malloc( sizeof( struct tcpstreaminfo ));
00238        } else {
00239               tcpsip = (struct tcpstreaminfo *)realloc( sip->si_streaminfo,
00240                   ( sip->si_count + 1 ) * sizeof( struct tcpstreaminfo ));
00241        }
00242 
00243        if ( tcpsip != NULL ) {
00244               tcpsip[ sip->si_count ].tcpsi_stream = (tcpstream *)sb->sb_sd;
00245               tcpsip[ sip->si_count ].tcpsi_check_write = true;
00246               tcpsip[ sip->si_count ].tcpsi_is_write_ready = false;
00247               sip->si_streaminfo = tcpsip;
00248               ++sip->si_count;
00249        }
00250 }
00251 
00252 
00253 void
00254 nsldapi_mark_select_read( LDAP *ld, Sockbuf *sb )
00255 {
00256        struct selectinfo           *sip;
00257        struct tcpstreaminfo *tcpsip;
00258        short                              i;
00259        
00260        LDAPDebug( LDAP_DEBUG_TRACE, "mark_select_read: stream %x\n", (tcpstream *)sb->sb_sd, 0, 0 );
00261 
00262        if (( sip = (struct selectinfo *)ld->ld_selectinfo ) == NULL ) {
00263               return;
00264        }
00265 
00266        if ( ld->ld_select_fn != NULL ) {         
00267               if ( !FD_ISSET( (int)sb->sb_sd, &sip->si_stdinfo.ssi_readfds )) {
00268                      FD_SET( (int)sb->sb_sd, &sip->si_stdinfo.ssi_readfds );
00269               }
00270               return;
00271        }
00272 
00273        for ( i = 0; i < sip->si_count; ++i ) {   /* make sure stream is not already in the list... */
00274               if ( sip->si_streaminfo[ i ].tcpsi_stream == (tcpstream *)sb->sb_sd ) {
00275                      sip->si_streaminfo[ i ].tcpsi_check_read = true;
00276                      sip->si_streaminfo[ i ].tcpsi_is_read_ready = false;
00277             sip->si_streaminfo[ i ].tcpsi_check_write = true;
00278             sip->si_streaminfo[ i ].tcpsi_is_write_ready = false;
00279                      return;
00280               }
00281        }
00282 
00283        /* add a new stream element to our array... */
00284        if ( sip->si_count <= 0 ) {
00285               tcpsip = (struct tcpstreaminfo *)malloc( sizeof( struct tcpstreaminfo ));
00286        } else {
00287               tcpsip = (struct tcpstreaminfo *)realloc( sip->si_streaminfo,
00288                             ( sip->si_count + 1 ) * sizeof( struct tcpstreaminfo ));
00289        }
00290        
00291        if ( tcpsip != NULL ) {
00292               tcpsip[ sip->si_count ].tcpsi_stream = (tcpstream *)sb->sb_sd;
00293               tcpsip[ sip->si_count ].tcpsi_check_read = true;
00294               tcpsip[ sip->si_count ].tcpsi_is_read_ready = false;
00295               tcpsip[ sip->si_count ].tcpsi_check_write = true;
00296               tcpsip[ sip->si_count ].tcpsi_is_write_ready = false;
00297               sip->si_streaminfo = tcpsip;
00298               ++sip->si_count;
00299        }
00300 }
00301 
00302 
00303 void
00304 nsldapi_mark_select_clear( LDAP *ld, Sockbuf *sb )
00305 {
00306        struct selectinfo    *sip;
00307        short                       i;
00308 
00309        LDAPDebug( LDAP_DEBUG_TRACE, "mark_select_clear: stream %x\n", (tcpstream *)sb->sb_sd, 0, 0 );
00310 
00311        if (( sip = (struct selectinfo *)ld->ld_selectinfo ) == NULL ) {
00312               return;
00313        }
00314 
00315        if ( ld->ld_select_fn != NULL ) {
00316               FD_CLR( (int)sb->sb_sd, &sip->si_stdinfo.ssi_writefds );
00317               FD_CLR( (int)sb->sb_sd, &sip->si_stdinfo.ssi_readfds );
00318 
00319        } else if ( sip->si_count > 0 && sip->si_streaminfo != NULL ) {
00320               for ( i = 0; i < sip->si_count; ++i ) {
00321                      if ( sip->si_streaminfo[ i ].tcpsi_stream == (tcpstream *)sb->sb_sd ) {
00322                             break;
00323                      }
00324               }
00325               if ( i < sip->si_count ) {
00326                      --sip->si_count;
00327                      for ( ; i < sip->si_count; ++i ) {
00328                             sip->si_streaminfo[ i ] = sip->si_streaminfo[ i + 1 ];
00329                      }
00330                      /* we don't bother to use realloc to make the si_streaminfo array smaller */
00331               }
00332        }
00333 }
00334 
00335 
00336 int
00337 nsldapi_is_write_ready( LDAP *ld, Sockbuf *sb )
00338 {
00339     struct selectinfo    *sip;
00340     short                i;
00341     
00342     if (( sip = (struct selectinfo *)ld->ld_selectinfo ) == NULL ) {
00343         return( 0 );    /* punt */
00344     }
00345 
00346     if ( ld->ld_select_fn != NULL ) {
00347         return( FD_ISSET( (int)sb->sb_sd, &sip->si_stdinfo.ssi_use_writefds));
00348     }
00349 
00350     if ( sip->si_count > 0 && sip->si_streaminfo != NULL ) {
00351         for ( i = 0; i < sip->si_count; ++i ) {
00352             if ( sip->si_streaminfo[ i ].tcpsi_stream == (tcpstream *)sb->sb_sd ) {
00353 #ifdef LDAP_DEBUG
00354                 if ( sip->si_streaminfo[ i ].tcpsi_is_write_ready ) {
00355                     LDAPDebug( LDAP_DEBUG_TRACE, "is_write_ready: stream %x READY\n",
00356                             (tcpstream *)sb->sb_sd, 0, 0 );
00357                 } else {
00358                     LDAPDebug( LDAP_DEBUG_TRACE, "is_write_ready: stream %x Not Ready\n",
00359                             (tcpstream *)sb->sb_sd, 0, 0 );
00360                 }
00361 #endif /* LDAP_DEBUG */
00362                 return( sip->si_streaminfo[ i ].tcpsi_is_write_ready ? 1 : 0 );
00363             }
00364         }
00365     }
00366 
00367     LDAPDebug( LDAP_DEBUG_TRACE, "is_write_ready: stream %x: NOT FOUND\n", (tcpstream *)sb->sb_sd, 0, 0 );
00368     return( 0 );
00369 }
00370 
00371 
00372 int
00373 nsldapi_is_read_ready( LDAP *ld, Sockbuf *sb )
00374 {
00375        struct selectinfo    *sip;
00376        short                       i;
00377        
00378        if (( sip = (struct selectinfo *)ld->ld_selectinfo ) == NULL ) {
00379               return( 0 );  /* punt */
00380        }
00381 
00382        if ( ld->ld_select_fn != NULL ) {
00383               return( FD_ISSET( (int)sb->sb_sd, &sip->si_stdinfo.ssi_use_readfds ));
00384        }
00385 
00386        if ( sip->si_count > 0 && sip->si_streaminfo != NULL ) {
00387               for ( i = 0; i < sip->si_count; ++i ) {
00388                      if ( sip->si_streaminfo[ i ].tcpsi_stream == (tcpstream *)sb->sb_sd ) {
00389 #ifdef LDAP_DEBUG
00390                             if ( sip->si_streaminfo[ i ].tcpsi_is_read_ready ) {
00391                                    LDAPDebug( LDAP_DEBUG_TRACE, "is_read_ready: stream %x READY\n",
00392                                                  (tcpstream *)sb->sb_sd, 0, 0 );
00393                             } else {
00394                                    LDAPDebug( LDAP_DEBUG_TRACE, "is_read_ready: stream %x Not Ready\n",
00395                                                  (tcpstream *)sb->sb_sd, 0, 0 );
00396                             }
00397 #endif /* LDAP_DEBUG */
00398                             return( sip->si_streaminfo[ i ].tcpsi_is_read_ready ? 1 : 0 );
00399                      }
00400               }
00401        }
00402 
00403        LDAPDebug( LDAP_DEBUG_TRACE, "is_read_ready: stream %x: NOT FOUND\n", (tcpstream *)sb->sb_sd, 0, 0 );
00404        return( 0 );
00405 }
00406 
00407 
00408 void *
00409 nsldapi_new_select_info()
00410 {
00411        struct selectinfo    *sip;
00412               
00413        if (( sip = (struct selectinfo *)calloc( 1, sizeof( struct selectinfo ))) != NULL ) {
00414               FD_ZERO( &sip->si_stdinfo.ssi_readfds );
00415               FD_ZERO( &sip->si_stdinfo.ssi_writefds );
00416        }
00417 
00418        return( (void *)sip );
00419 }
00420 
00421 
00422 void
00423 nsldapi_free_select_info( void *sip )
00424 {
00425        if ( sip != NULL ) {
00426               free( sip );
00427        }
00428 }
00429 
00430 
00431 int
00432 nsldapi_do_ldap_select( LDAP *ld, struct timeval *timeout )
00433 {
00434        struct selectinfo    *sip;
00435        Boolean                            ready, gotselecterr;
00436        unsigned long        ticks, endticks;
00437        short                       i, err;
00438        static int                  tblsize = 0;
00439        EventRecord                 dummyEvent;
00440 
00441        LDAPDebug( LDAP_DEBUG_TRACE, "do_ldap_select\n", 0, 0, 0 );
00442 
00443        if (( sip = (struct selectinfo *)ld->ld_selectinfo ) == NULL ) {
00444               return( -1 );
00445        }
00446 
00447        if ( ld->ld_select_fn != NULL ) {
00448               if ( tblsize == 0 ) {
00449                      tblsize = FD_SETSIZE - 1;
00450               }
00451 
00452               sip->si_stdinfo.ssi_use_readfds = sip->si_stdinfo.ssi_readfds;
00453               sip->si_stdinfo.ssi_use_writefds = sip->si_stdinfo.ssi_writefds;
00454 
00455               return( ld->ld_select_fn( tblsize, &sip->si_stdinfo.ssi_use_readfds,
00456                   &sip->si_stdinfo.ssi_use_writefds, NULL, timeout ));
00457        }
00458 
00459        if ( sip->si_count == 0 ) {
00460               return( 1 );
00461        }
00462 
00463        if ( timeout != NULL ) {
00464               endticks = 60 * timeout->tv_sec + ( 60 * timeout->tv_usec ) / 1000000 + TickCount();
00465        }
00466 
00467        for ( i = 0; i < sip->si_count; ++i ) {
00468               if ( sip->si_streaminfo[ i ].tcpsi_check_read ) {
00469                      sip->si_streaminfo[ i ].tcpsi_is_read_ready = false;
00470               }
00471         if ( sip->si_streaminfo[ i ].tcpsi_check_write ) {
00472             sip->si_streaminfo[ i ].tcpsi_is_write_ready = false;
00473         }
00474        }
00475 
00476        ready = gotselecterr = false;
00477        do {
00478               for ( i = 0; i < sip->si_count; ++i ) {
00479                      if ( sip->si_streaminfo[ i ].tcpsi_check_read && !sip->si_streaminfo[ i ].tcpsi_is_read_ready ) {
00480                             if (( err = tcpreadready( sip->si_streaminfo[ i ].tcpsi_stream )) > 0 ) {
00481                                    sip->si_streaminfo[ i ].tcpsi_is_read_ready = ready = true;
00482                 } else if ( err < 0 ) {
00483                     gotselecterr = true;
00484                 }
00485             }
00486                      if ( sip->si_streaminfo[ i ].tcpsi_check_write && !sip->si_streaminfo[ i ].tcpsi_is_write_ready ) {
00487                                    if (( err = tcpwriteready( sip->si_streaminfo[ i ].tcpsi_stream )) > 0 ) {
00488                                                  sip->si_streaminfo[ i ].tcpsi_is_write_ready = ready = true;
00489                                    } else if ( err < 0 ) {
00490                                                  gotselecterr = true;
00491                                    }
00492                      }
00493               }
00494 
00495               if ( !ready && !gotselecterr ) {
00496                      (void)WaitNextEvent(nullEvent, &dummyEvent, 1, NULL);
00497                      ticks = TickCount();
00498               }
00499        } while ( !ready && !gotselecterr && ( timeout == NULL || ticks < endticks ));
00500 
00501        LDAPDebug( LDAP_DEBUG_TRACE, "do_ldap_select returns %d\n", ready ? 1 : ( gotselecterr ? -1 : 0 ), 0, 0 );
00502        return( ready ? 1 : ( gotselecterr ? -1 : 0 ));
00503 }