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.
10 #include <sys/types.h>
11 #include <sys/socket.h>
12 #include <netinet/in.h>
13 #include <arpa/inet.h>
18 #include <netinet/tcp.h>
21 #include "connection.h"
29 #define NEW_CONN() NEW( connection_s )
30 #define FREE_CONN( cop ) FREE( cop )
33 * Get a new connection request and initialize 'cp' appropriately
35 static status_e get_connection( struct service *sp, connection_s *cp )
37 struct service_config *scp = SVC_CONF( sp );
39 const char *func = "get_connection" ;
42 if( SC_IPV4(scp) ) sin_len = sizeof(struct sockaddr_in);
43 if( SC_IPV6(scp) ) sin_len = sizeof(struct sockaddr_in6);
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.
51 if( SC_WAITS( scp ) ) {
52 cp->co_descriptor = SVC_FD( sp );
54 cp->co_descriptor = accept( SVC_FD( sp ), &(cp->co_remote_address.sa),
56 if (cp->co_descriptor != -1)
57 M_SET( cp->co_flags, COF_NEW_DESCRIPTOR ) ;
60 if ( cp->co_descriptor == -1 )
62 if ((errno == EMFILE) || (errno == ENFILE))
63 cps_service_stop(sp, "no available descriptors");
65 msg( LOG_ERR, func, "service %s, accept: %m", SVC_ID( sp ) ) ;
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));
74 if( SC_KEEPALIVE( scp ) && (SC_PROTOVAL( scp ) == IPPROTO_TCP) )
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));
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)) )
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) );
92 M_SET( cp->co_flags, COF_HAVE_ADDRESS ) ;
96 if ( SVC_SOCKET_TYPE( sp ) == SOCK_DGRAM )
101 * This trick is done to get the remote address.
102 * select(2) guaranteed that we won't block on the recvfrom
104 if ( recvfrom( SVC_FD( sp ), &t_ch, 1, MSG_PEEK,
105 &cp->co_remote_address.sa, &sin_len ) == -1 )
107 msg( LOG_ERR, func, "service %s, recvfrom: %m", SVC_ID( sp ) ) ;
110 M_SET( cp->co_flags, COF_HAVE_ADDRESS ) ;
113 cp->co_descriptor = SVC_FD( sp ) ;
122 * Get a connection for the specified service and return a pointer
123 * to a new connection_s
125 connection_s *conn_new( struct service *sp )
127 connection_s new_conn ;
129 const char *func = "conn_new" ;
134 * The reason we first get the connection and then allocate a
135 * 'connection_s' is because we want to always consume some input.
137 if ( get_connection( sp, &new_conn ) == FAILED )
140 new_conn.co_sp = sp ;
143 if ( SVC_WAITS( sp ) )
147 if ( cp == CONN_NULL )
149 out_of_memory( func ) ;
150 conn_free( &new_conn, 0 ) ;
152 return( CONN_NULL ) ;
154 memcpy(cp, &new_conn, sizeof(connection_s));
160 * Release the specified connection.
161 * Certain actions may be performed before doing this:
162 * - drain of a single UDP packet if the socket type is SOCK_DGRAM
164 void conn_free( connection_s *cp, int release_mem )
166 struct service *sp = cp->co_sp ;
171 msg( LOG_INFO, "conn_free", "freeing connection") ;
173 if( (SVC_SOCKET_TYPE( sp ) == SOCK_DGRAM) && (SVC_IS_ACTIVE( sp )) )
174 drain( cp->co_descriptor ) ;
176 if ( SVC_RELE( sp ) == 0 ) {
177 pset_remove( SERVICES( ps ), sp ) ;
190 /* This returns a pointer to a local static stack variable.
191 * The behavior is a remnant of inet_ntoa() behavior.
193 const char *conn_addrstr( const connection_s *cp )
195 static char name[NI_MAXHOST];
196 unsigned int len = 0;
198 if( !M_IS_SET( (cp)->co_flags, COF_HAVE_ADDRESS ) )
199 return "<no address>";
201 if( cp->co_remote_address.sa.sa_family == AF_INET )
202 len = sizeof(struct sockaddr_in);
203 else if( cp->co_remote_address.sa.sa_family == AF_INET6 )
204 len = sizeof(struct sockaddr_in6);
206 if( getnameinfo( &cp->co_remote_address.sa, len,
207 name, NI_MAXHOST, NULL, 0, NI_NUMERICHOST ) ) {
208 return "<no address>";
213 void conn_dump( const connection_s *cp, int fd )
215 const char *name = conn_addrstr( cp );
217 tabprint( fd, 1, "service = %s\n", SVC_ID( cp->co_sp ) ) ;
218 tabprint( fd, 1, "descriptor = %d\n", cp->co_descriptor ) ;
219 #if defined(__GNUC__) && !defined(__arch64__) && !defined(__alpha__)
220 tabprint( fd, 1, "flags = %#llx\n", cp->co_flags ) ;
222 tabprint( fd, 1, "flags = %#lx\n", cp->co_flags ) ;
224 tabprint( fd, 1, "remote_address = %s,%d\n", name,
225 ntohs( cp->co_remote_address.sa_in.sin_port ) ) ;