]> git.sur5r.net Git - openldap/blob - libraries/libldap/os-local.c
df4196266f97ab475dc435d259a8219b7e5abdce
[openldap] / libraries / libldap / os-local.c
1 /* $OpenLDAP$ */
2 /*
3  * Copyright 1998-2000 The OpenLDAP Foundation, All Rights Reserved.
4  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
5  */
6 /*  Portions
7  *  Copyright (c) 1995 Regents of the University of Michigan.
8  *  All rights reserved.
9  *  Copyright (c) 1999 PADL Software Pty Ltd.
10  *  os-ip.c -- platform-specific domain socket code
11  */
12
13
14 #include "portable.h"
15
16 #ifdef LDAP_PF_UNIX
17
18 #include <stdio.h>
19
20 #include <ac/stdlib.h>
21
22 #include <ac/errno.h>
23 #include <ac/socket.h>
24 #include <ac/string.h>
25 #include <ac/time.h>
26 #include <ac/unistd.h>
27
28 /* XXX non-portable */
29 #include <sys/stat.h>
30
31 #ifdef HAVE_IO_H
32 #include <io.h>
33 #endif /* HAVE_IO_H */
34
35 #include "ldap-int.h"
36
37 /* int ldap_int_tblsize = 0; */
38
39 #define oslocal_debug(ld,fmt,arg1,arg2,arg3) \
40 do { \
41         ldap_log_printf(ld, LDAP_DEBUG_TRACE, fmt, arg1, arg2, arg3); \
42 } while(0)
43
44 static void
45 ldap_pvt_set_errno(int err)
46 {
47         errno = err;
48 }
49
50 static int
51 ldap_pvt_ndelay_on(LDAP *ld, int fd)
52 {
53         oslocal_debug(ld, "ldap_ndelay_on: %d\n",fd,0,0);
54         return ber_pvt_socket_set_nonblock( fd, 1 );
55 }
56    
57 static int
58 ldap_pvt_ndelay_off(LDAP *ld, int fd)
59 {
60         oslocal_debug(ld, "ldap_ndelay_off: %d\n",fd,0,0);
61         return ber_pvt_socket_set_nonblock( fd, 0 );
62 }
63
64 static ber_socket_t
65 ldap_pvt_socket(LDAP *ld)
66 {
67         ber_socket_t s = socket(AF_UNIX, SOCK_STREAM, 0);
68         oslocal_debug(ld, "ldap_new_socket: %d\n",s,0,0);
69         return ( s );
70 }
71
72 static int
73 ldap_pvt_close_socket(LDAP *ld, int s)
74 {
75         oslocal_debug(ld, "ldap_close_socket: %d\n",s,0,0);
76         return tcp_close(s);
77 }
78
79 #undef TRACE
80 #define TRACE do { \
81         oslocal_debug(ld, \
82                 "ldap_is_socket_ready: errror on socket %d: errno: %d (%s)\n", \
83                 s, \
84                 errno, \
85                 strerror(errno) ); \
86 } while( 0 )
87
88 /*
89  * check the socket for errors after select returned.
90  */
91 static int
92 ldap_pvt_is_socket_ready(LDAP *ld, int s)
93 {
94         oslocal_debug(ld, "ldap_is_sock_ready: %d\n",s,0,0);
95
96 #if defined( notyet ) /* && defined( SO_ERROR ) */
97 {
98         int so_errno;
99         int dummy = sizeof(so_errno);
100         if ( getsockopt( s, SOL_SOCKET, SO_ERROR, &so_errno, &dummy ) == -1 ) {
101                 return -1;
102         }
103         if ( so_errno ) {
104                 ldap_pvt_set_errno(so_errno);
105                 TRACE;
106                 return -1;
107         }
108         return 0;
109 }
110 #else
111 {
112         /* error slippery */
113         struct sockaddr_un sun;
114         char ch;
115         int dummy = sizeof(sun);
116         if ( getpeername( s, (struct sockaddr *) &sun, &dummy ) == -1 ) {
117                 /* XXX: needs to be replace with ber_stream_read() */
118                 read(s, &ch, 1);
119                 TRACE;
120                 return -1;
121         }
122         return 0;
123 }
124 #endif
125         return -1;
126 }
127 #undef TRACE
128
129 static int
130 ldap_pvt_connect(LDAP *ld, ber_socket_t s, struct sockaddr_un *sun, int async)
131 {
132         struct timeval  tv, *opt_tv=NULL;
133         fd_set          wfds, *z=NULL;
134
135         if ( (opt_tv = ld->ld_options.ldo_tm_net) != NULL ) {
136                 tv.tv_usec = opt_tv->tv_usec;
137                 tv.tv_sec = opt_tv->tv_sec;
138         }
139
140         oslocal_debug(ld, "ldap_connect_timeout: fd: %d tm: %ld async: %d\n",
141                         s, opt_tv ? tv.tv_sec : -1L, async);
142
143         if ( ldap_pvt_ndelay_on(ld, s) == -1 )
144                 return ( -1 );
145
146         if ( connect(s, (struct sockaddr *) sun, sizeof(struct sockaddr_un)) == 0 )
147         {
148                 if ( ldap_pvt_ndelay_off(ld, s) == -1 )
149                         return ( -1 );
150                 return ( 0 );
151         }
152
153         if ( errno != EINPROGRESS && errno != EWOULDBLOCK ) {
154                 return ( -1 );
155         }
156         
157 #ifdef notyet
158         if ( async ) return ( -2 );
159 #endif
160
161         FD_ZERO(&wfds);
162         FD_SET(s, &wfds );
163
164         if ( select(ldap_int_tblsize, z, &wfds, z, opt_tv ? &tv : NULL) == -1)
165                 return ( -1 );
166
167         if ( FD_ISSET(s, &wfds) ) {
168                 if ( ldap_pvt_is_socket_ready(ld, s) == -1 )
169                         return ( -1 );
170                 if ( ldap_pvt_ndelay_off(ld, s) == -1 )
171                         return ( -1 );
172                 return ( 0 );
173         }
174         oslocal_debug(ld, "ldap_connect_timeout: timed out\n",0,0,0);
175         ldap_pvt_set_errno( ETIMEDOUT );
176         return ( -1 );
177 }
178
179 int
180 ldap_connect_to_path(LDAP *ld, Sockbuf *sb, const char *path, int async)
181 {
182         struct sockaddr_un      server;
183         ber_socket_t            s = AC_SOCKET_INVALID;
184         int                     rc, i, len;
185         char                    *ha_buf=NULL, *p, *q;
186
187         oslocal_debug(ld, "ldap_connect_to_path\n",0,0,0);
188
189         if ( (s = ldap_pvt_socket( ld )) == -1 ) {
190                 return -1;
191         }
192
193         if ( path == NULL || path[0] == '\0' ) {
194                 path = "/tmp/.ldap-sock";
195         } else {
196                 if ( strlen(path) > (sizeof( server.sun_path ) - 1) ) {
197                         ldap_pvt_set_errno( ENAMETOOLONG );
198                         return -1;
199                 }
200         }
201
202         oslocal_debug(ld, "ldap_connect_to_path: Trying %s\n", path, 0, 0);
203
204         memset( &server, 0, sizeof(server) );
205         server.sun_family = AF_UNIX;
206         strcpy( server.sun_path, path );
207
208         rc = ldap_pvt_connect(ld, s, &server, async);
209
210         if (rc == 0) {
211                 ber_sockbuf_ctrl( sb, LBER_SB_OPT_SET_FD, (void *)&s );
212         } else {
213                 ldap_pvt_close_socket(ld, s);
214         }
215         return rc;
216 }
217 #else
218 static int dummy;
219 #endif /* LDAP_PF_UNIX */