1 /*
2  * (c) Copyright 1992 by Panagiotis Tsirigotis
3  * (c) Sections Copyright 1998-2001 by Rob Braun
4  * All rights reserved.  The file named COPYRIGHT specifies the terms
5  * and conditions for redistribution.
6  */
7 
8 
9 #include "config.h"
10 #include <sys/types.h>
11 #include <sys/socket.h>
12 #include <netinet/in.h>
13 #include <arpa/inet.h>
14 #include <syslog.h>
15 #include <stdlib.h>
16 #include <unistd.h>
17 
18 #include <netinet/tcp.h>
19 
20 #include "sio.h"
21 #include "connection.h"
22 #include "sconf.h"
23 #include "msg.h"
24 #include "main.h"
25 #include "state.h"
26 #include "special.h"
27 #include "access.h"
28 
29 #define NEW_CONN()            NEW( connection_s )
30 #define FREE_CONN( cop )      FREE( cop )
31 
32 /*
33  * Get a new connection request and initialize 'cp' appropriately
34  */
get_connection(struct service * sp,connection_s * cp)35 static status_e get_connection( struct service *sp, connection_s *cp )
36 {
37    struct service_config *scp = SVC_CONF( sp );
38    socklen_t sin_len;
39    const char *func = "get_connection" ;
40    int on = 1;
41 
42    if( SC_IPV4(scp) ) sin_len = sizeof(struct sockaddr_in);
43    if( SC_IPV6(scp) ) sin_len = sizeof(struct sockaddr_in6);
44 
45    if ( SVC_SOCKET_TYPE( sp ) == SOCK_STREAM ) {
46       /* If it's a TCP socket, and we're set to wait, the accept is
47        * done by the child process.  Don't set NEW_DESCRIPTOR, since
48        * there isn't one.  The descriptor will be/was removed from
49        * the descriptor set in svc_suspend and re-enabled in svc_resume.
50        */
51       if( SC_WAITS( scp ) ) {
52          cp->co_descriptor = SVC_FD( sp );
53       } else {
54          cp->co_descriptor = accept( SVC_FD( sp ), &(cp->co_remote_address.sa),
55                                      &sin_len ) ;
56 	 if (cp->co_descriptor != -1)
57              M_SET( cp->co_flags, COF_NEW_DESCRIPTOR ) ;
58       }
59 
60       if ( cp->co_descriptor == -1 )
61       {
62 	 if ((errno == EMFILE) || (errno == ENFILE))
63 	     cps_service_stop(sp, "no available descriptors");
64 	 else
65              msg( LOG_ERR, func, "service %s, accept: %m", SVC_ID( sp ) ) ;
66          return( FAILED ) ;
67       }
68 
69       if( SC_NODELAY( scp ) && (SC_PROTOVAL( scp ) == IPPROTO_TCP) )
70          if( setsockopt(SVC_FD(sp), IPPROTO_TCP, TCP_NODELAY,
71                         (char *)&on, sizeof( on ) ) < 0 )
72             msg( LOG_WARNING, func, "service %s, setsockopt: %m", SVC_ID(sp));
73 
74       if( SC_KEEPALIVE( scp ) && (SC_PROTOVAL( scp ) == IPPROTO_TCP) )
75       {
76          if( setsockopt(SVC_FD(sp), SOL_SOCKET, SO_KEEPALIVE,
77                         (char *)&on, sizeof( on ) ) < 0 )
78             msg( LOG_WARNING, func, "service %s, setsockopt: %m", SVC_ID(sp));
79       }
80 
81       if( SC_IPV6(scp) && !(SC_V6ONLY( scp ))  &&
82          (IN6_IS_ADDR_V4MAPPED(&cp->co_remote_address.sa_in6.sin6_addr) ||
83 	  IN6_IS_ADDR_V4COMPAT(&cp->co_remote_address.sa_in6.sin6_addr)) )
84       {
85          int af = AF_INET;
86          if( setsockopt(cp->co_descriptor, IPPROTO_IPV6,
87                IPV6_ADDRFORM, &af, sizeof( af ) ) ) {
88             if( debug.on ) msg( LOG_WARNING, func, "service %s, IPV6_ADDRFORM setsockopt() failed: %m", SVC_ID( sp) );
89          }
90       }
91 
92       M_SET( cp->co_flags, COF_HAVE_ADDRESS ) ;
93    }
94    else
95    {
96       if ( SVC_SOCKET_TYPE( sp ) == SOCK_DGRAM )
97       {
98          char t_ch ;
99 	 ssize_t val;
100 
101          /*
102           * This trick is done to get the remote address.
103           * select(2) guaranteed that we won't block on the recvfrom
104           */
105 	 val = recvfrom( SVC_FD( sp ), &t_ch, 1, MSG_PEEK,
106                               &cp->co_remote_address.sa, &sin_len );
107          if ( val == (ssize_t)-1 )
108          {
109             msg( LOG_ERR, func, "service %s, recvfrom: %m", SVC_ID( sp ) ) ;
110             return( FAILED ) ;
111          }
112          M_SET( cp->co_flags, COF_HAVE_ADDRESS ) ;
113       }
114 
115       cp->co_descriptor = SVC_FD( sp ) ;
116    }
117 
118    return( OK ) ;
119 }
120 
121 
122 
123 /*
124  * Get a connection for the specified service and return a pointer
125  * to a new connection_s
126  */
conn_new(struct service * sp)127 connection_s *conn_new( struct service *sp )
128 {
129    connection_s    new_conn ;
130    connection_s   *cp ;
131    const char     *func = "conn_new" ;
132 
133    CLEAR( new_conn ) ;
134 
135    /*
136     * The reason we first get the connection and then allocate a
137     * 'connection_s' is because we want to always consume some input.
138     */
139    if ( get_connection( sp, &new_conn ) == FAILED )
140       return( NULL ) ;
141 
142    new_conn.co_sp = sp ;
143    SVC_HOLD( sp ) ;
144 
145    if ( SVC_WAITS( sp ) )
146       svc_suspend( sp ) ;
147 
148    cp = NEW_CONN() ;
149    if ( cp == CONN_NULL )
150    {
151       out_of_memory( func ) ;
152       conn_free( &new_conn, 0 ) ;
153       CLEAR( new_conn ) ;
154       return( CONN_NULL ) ;
155    }
156    memcpy(cp, &new_conn, sizeof(connection_s));
157    return( cp ) ;
158 }
159 
160 
161 /*
162  * Release the specified connection.
163  * Certain actions may be performed before doing this:
164  *      - drain of a single UDP packet if the socket type is SOCK_DGRAM
165  */
conn_free(connection_s * cp,int release_mem)166 void conn_free( connection_s *cp, int release_mem )
167 {
168    struct service *sp = cp->co_sp ;
169 
170    if( cp == NULL )
171       return;
172       if( debug.on )
173          msg( LOG_INFO, "conn_free", "freeing connection") ;
174 
175    if( (SVC_SOCKET_TYPE( sp ) == SOCK_DGRAM) && (SVC_IS_ACTIVE( sp )) )
176       drain( cp->co_descriptor ) ;
177 
178    if ( SVC_RELE( sp ) == 0 ) {
179       pset_remove( SERVICES( ps ), sp ) ;
180       svc_release( sp );
181    }
182    cp->co_sp = NULL;
183 
184    CONN_CLOSE( cp ) ;
185 
186    CLEAR( *cp ) ;
187    if (release_mem) {
188       FREE_CONN( cp ) ;
189    }
190 }
191 
192 /* This returns a pointer to a local static stack variable.
193  * The behavior is a remnant of inet_ntoa() behavior.
194  */
conn_addrstr(const connection_s * cp)195 const char *conn_addrstr( const connection_s *cp )
196 {
197    static char name[NI_MAXHOST];
198    unsigned int len = 0;
199 
200    if( !M_IS_SET( (cp)->co_flags, COF_HAVE_ADDRESS ) )
201       return "<no address>";
202 
203    if( cp->co_remote_address.sa.sa_family == AF_INET )
204       len = sizeof(struct sockaddr_in);
205    else if( cp->co_remote_address.sa.sa_family == AF_INET6 )
206       len = sizeof(struct sockaddr_in6);
207 
208    if( getnameinfo( &cp->co_remote_address.sa, len,
209          name, NI_MAXHOST, NULL, 0, NI_NUMERICHOST ) ) {
210       return "<no address>";
211    }
212    return name;
213 }
214 
conn_dump(const connection_s * cp,int fd)215 void conn_dump( const connection_s *cp, int fd )
216 {
217    const char *name = conn_addrstr( cp );
218 
219    tabprint( fd, 1, "service = %s\n", SVC_ID( cp->co_sp ) ) ;
220    tabprint( fd, 1, "descriptor = %d\n", cp->co_descriptor ) ;
221 #if defined(__GNUC__) && !defined(__arch64__) && !defined(__alpha__)
222    tabprint( fd, 1, "flags = %#llx\n", cp->co_flags ) ;
223 #else
224    tabprint( fd, 1, "flags = %#lx\n", cp->co_flags ) ;
225 #endif
226    tabprint( fd, 1, "remote_address = %s,%d\n", name,
227                               ntohs( cp->co_remote_address.sa_in.sin_port ) ) ;
228 }
229 
230