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