]> arthur.barton.de Git - ngircd-alex.git/blob - src/ngircd/conn.c
- diverse Erweiterungen und Verbesserungen (u.a. sind nun mehrere
[ngircd-alex.git] / src / ngircd / conn.c
1 /*
2  * ngIRCd -- The Next Generation IRC Daemon
3  * Copyright (c)2001 by Alexander Barton (alex@barton.de)
4  *
5  * Dieses Programm ist freie Software. Sie koennen es unter den Bedingungen
6  * der GNU General Public License (GPL), wie von der Free Software Foundation
7  * herausgegeben, weitergeben und/oder modifizieren, entweder unter Version 2
8  * der Lizenz oder (wenn Sie es wuenschen) jeder spaeteren Version.
9  * Naehere Informationen entnehmen Sie bitter der Datei COPYING. Eine Liste
10  * der an comBase beteiligten Autoren finden Sie in der Datei AUTHORS.
11  *
12  * $Id: conn.c,v 1.2 2001/12/12 23:32:02 alex Exp $
13  *
14  * connect.h: Verwaltung aller Netz-Verbindungen ("connections")
15  *
16  * $Log: conn.c,v $
17  * Revision 1.2  2001/12/12 23:32:02  alex
18  * - diverse Erweiterungen und Verbesserungen (u.a. sind nun mehrere
19  *   Verbindungen und Listen-Sockets moeglich).
20  *
21  * Revision 1.1  2001/12/12 17:18:38  alex
22  * - Modul zur Verwaltung aller Netzwerk-Verbindungen begonnen.
23  */
24
25
26 #include <portab.h>
27 #include "global.h"
28
29 #include <imp.h>
30 #include <assert.h>
31 #include <stdio.h>
32 #include <unistd.h>
33 #include <errno.h>
34 #include <fcntl.h>
35 #include <string.h>
36 #include <sys/socket.h> 
37 #include <sys/time.h>
38 #include <sys/types.h> 
39 #include <netinet/in.h>
40 #include <arpa/inet.h>
41
42 #ifdef HAVE_STDINT_H
43 #include <stdint.h>                     /* u.a. fuer Mac OS X */
44 #endif
45
46 #include "ngircd.h"
47 #include "log.h"
48 #include "tool.h"
49
50 #include <exp.h>
51 #include "conn.h"
52
53
54 #define MAX_CONNECTIONS 100
55
56
57 typedef struct _Connection
58 {
59         INT sock;                       /* Socket Handle */
60         struct sockaddr_in addr;        /* Adresse des Client */
61         FILE *fd;                       /* FILE Handle */
62 } CONNECTION;
63
64
65 LOCAL VOID Handle_Socket( INT sock );
66
67 LOCAL VOID New_Connection( INT Sock );
68
69 LOCAL INT Socket2Index( INT Sock );
70
71 LOCAL VOID Close_Connection( INT Idx );
72 LOCAL VOID Read_Data( INT Idx );
73
74
75 LOCAL fd_set My_Listener;
76 LOCAL fd_set My_Sockets;
77
78 LOCAL INT My_Max_Fd;
79
80 LOCAL CONNECTION My_Connections[MAX_CONNECTIONS];
81
82
83 GLOBAL VOID Conn_Init( VOID )
84 {
85         INT i;
86
87         /* zu Beginn haben wir keine Verbindungen */
88         FD_ZERO( &My_Listener );
89         FD_ZERO( &My_Sockets );
90         
91         My_Max_Fd = 0;
92         
93         /* Connection-Struktur initialisieren */
94         for( i = 0; i < MAX_CONNECTIONS; i++ )
95         {
96                 My_Connections[i].sock = -1;
97                 My_Connections[i].fd = NULL;
98         }
99 } /* Conn_Init */
100
101
102 GLOBAL VOID Conn_Exit( VOID )
103 {
104         INT idx, i;
105         
106         /* Sockets schliessen */
107         for( i = 0; i < My_Max_Fd + 1; i++ )
108         {
109                 if( FD_ISSET( i, &My_Sockets ))
110                 {
111                         for( idx = 0; idx < MAX_CONNECTIONS; idx++ )
112                         {
113                                 if( My_Connections[idx].sock == i ) break;
114                         }
115                         if( idx < MAX_CONNECTIONS ) Close_Connection( idx );
116                         else if( FD_ISSET( i, &My_Listener ))
117                         {
118                                 close( i );
119                                 Log( LOG_INFO, "Closed listening socket %d.", i );
120                         }
121                         else
122                         {
123                                 close( i );
124                                 Log( LOG_WARNING, "Unknown connection %d closed.", i );
125                         }
126                 }
127         }
128 } /* Conn_Exit */
129
130
131 GLOBAL BOOLEAN Conn_New_Listener( CONST INT Port )
132 {
133         /* Neuen Listen-Socket erzeugen: der Server wartet dann
134          * auf dem angegebenen Port auf Verbindungen. */
135
136         struct sockaddr_in addr;
137         INT sock, on = 1;
138
139         /* Server-"Listen"-Socket initialisieren */
140         memset( &addr, 0, sizeof( addr ));
141         addr.sin_family = AF_INET;
142         addr.sin_port = htons( Port );
143         addr.sin_addr.s_addr = htonl( INADDR_ANY );
144
145         /* Socket erzeugen */
146         sock = socket( PF_INET, SOCK_STREAM, 0);
147         if( socket < 0 )
148         {
149                 Log( LOG_ALERT, "Can't create socket: %s", strerror( errno ));
150                 return FALSE;
151         }
152
153         /* Socket-Optionen setzen */
154         if( fcntl( sock, F_SETFL, O_NONBLOCK ) != 0 )
155         {
156                 Log( LOG_ALERT, "Can't enable non-blocking mode: %s", strerror( errno ));
157                 close( sock );
158                 return FALSE;
159         }
160         if( setsockopt( sock, SOL_SOCKET, SO_REUSEADDR, &on, (socklen_t)sizeof( on )) != 0)
161         {
162                 Log( LOG_CRIT, "Can't set socket options: %s", strerror( errno ));
163                 /* dieser Fehler kann ignoriert werden. */
164         }
165
166         /* an Port binden */
167         if( bind( sock, (struct sockaddr *)&addr, (socklen_t)sizeof( addr )) != 0 )
168         {
169                 Log( LOG_ALERT, "Can't bind socket: %s", strerror( errno ));
170                 close( sock );
171                 return FALSE;
172         }
173
174         /* in "listen mode" gehen :-) */
175         if( listen( sock, 10 ) != 0 )
176         {
177                 Log( LOG_ALERT, "Can't listen on soecket: %s", strerror( errno ));
178                 close( sock );
179                 return FALSE;
180         }
181
182         /* Neuen Listener in Strukturen einfuegen */
183         FD_SET( sock, &My_Listener );
184         FD_SET( sock, &My_Sockets );
185         
186         if( sock > My_Max_Fd ) My_Max_Fd = sock;
187
188         Log( LOG_INFO, "Now listening on port %d, socked %d.", Port, sock );
189
190         return TRUE;
191 } /* Conn_New_Listener */
192
193
194 GLOBAL VOID Conn_Handler( VOID )
195 {
196         fd_set read_sockets;
197         INT i;
198         
199         read_sockets = My_Sockets;
200         if( select( My_Max_Fd + 1, &read_sockets, NULL, NULL, NULL ) == -1 )
201         {
202                 if( NGIRCd_Quit ) return;
203                 Log( LOG_ALERT, "select(): %s", strerror( errno ));
204                 return;
205         }
206         
207         for( i = 0; i < My_Max_Fd + 1; i++ )
208         {
209                 if( FD_ISSET( i, &read_sockets )) Handle_Socket( i );
210         }
211 } /* Conn_Handler */
212
213
214 LOCAL VOID Handle_Socket( INT Sock )
215 {
216         /* Aktivitaet auf einem Socket verarbeiten */
217
218         INT idx;
219
220         if( FD_ISSET( Sock, &My_Listener ))
221         {
222                 /* es ist einer unserer Listener-Sockets: es soll
223                  * also eine neue Verbindung aufgebaut werden. */
224
225                 New_Connection( Sock );
226         }
227         else
228         {
229                 /* Ein Client Socket: entweder ein User oder Server */
230                 
231                 idx = Socket2Index( Sock );
232                 Read_Data( idx );
233         }
234 } /* Handle_Socket */
235
236
237 LOCAL VOID New_Connection( INT Sock )
238 {
239         struct sockaddr_in new_addr;
240         INT new_sock, new_sock_len, idx;
241         FILE *fd;
242
243         new_sock_len = sizeof( new_addr );
244         new_sock = accept( Sock, (struct sockaddr *)&new_addr, &new_sock_len );
245         if( new_sock < 0 )
246         {
247                 Log( LOG_CRIT, "Can't accept connection: %s", strerror( errno ));
248                 return;
249         }
250                 
251         /* Freie Connection-Struktur suschen */
252         for( idx = 0; idx < MAX_CONNECTIONS; idx++ ) if( My_Connections[idx].sock < 0 ) break;
253         if( idx >= MAX_CONNECTIONS )
254         {
255                 Log( LOG_ALERT, "Connection limit (%d) reached!", MAX_CONNECTIONS );
256                 close( new_sock );
257                 return;
258         }
259
260         fd = fdopen( new_sock, "r+" );
261                 
262         /* Verbindung registrieren */
263         My_Connections[idx].sock = new_sock;
264         My_Connections[idx].fd = fd;
265         My_Connections[idx].addr = new_addr;
266
267         /* Neuen Socket registrieren */
268         FD_SET( new_sock, &My_Sockets );
269
270         if( new_sock > My_Max_Fd ) My_Max_Fd = new_sock;
271
272         fputs( "hello world!\n", fd ); fflush( fd );
273
274         Log( LOG_INFO, "Accepted connection from %s:%d.", inet_ntoa( new_addr.sin_addr ), ntohs( new_addr.sin_port));
275 } /* New_Connection */
276
277
278 LOCAL INT Socket2Index( INT Sock )
279 {
280         INT idx;
281         
282         for( idx = 0; idx < MAX_CONNECTIONS; idx++ ) if( My_Connections[idx].sock == Sock ) break;
283         assert( idx < MAX_CONNECTIONS );
284         
285         return idx;
286 } /* Socket2Index */
287
288
289 LOCAL VOID Close_Connection( INT Idx )
290 {
291         /* Verbindung schlie§en */
292
293         assert( My_Connections[Idx].sock >= 0 );
294         
295         if( fclose( My_Connections[Idx].fd ) != 0 )
296         {
297                 Log( LOG_ERR, "Error closing connection with %s:%d - %s", inet_ntoa( My_Connections[Idx].addr.sin_addr ), ntohs( My_Connections[Idx].addr.sin_port), strerror( errno ));
298         }
299         else
300         {
301                 Log( LOG_INFO, "Closed connection with %s:%d.", inet_ntoa( My_Connections[Idx].addr.sin_addr ), ntohs( My_Connections[Idx].addr.sin_port ));
302                 close( My_Connections[Idx].sock );
303         }
304
305         FD_CLR( My_Connections[Idx].sock, &My_Sockets );
306
307         My_Connections[Idx].sock = -1;
308         My_Connections[Idx].fd = NULL;
309 } /* Close_Connection */
310
311
312 LOCAL VOID Read_Data( INT Idx )
313 {
314         /* Daten von Socket einlesen */
315
316         #define SIZE 256
317         
318         CHAR buffer[SIZE];
319         
320         if( ! fgets( buffer, SIZE, My_Connections[Idx].fd ))
321         {
322                 Close_Connection( Idx );
323                 return;
324         }
325         
326         ngt_Trim_Str( buffer );
327         printf( " in: '%s'\n", buffer );
328 } /* Read_Data */
329
330
331 /* -eof- */