1 |
/* Copyright (C) 2003, 2004 Stephane Thiell |
2 |
* |
3 |
* This file is part of pxyservd (from pxys) |
4 |
* |
5 |
* This program is free software; you can redistribute it and/or |
6 |
* modify it under the terms of the GNU General Public License |
7 |
* as published by the Free Software Foundation; either version 2 |
8 |
* of the License, or (at your option) any later version. |
9 |
* |
10 |
* This program is distributed in the hope that it will be useful, |
11 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
13 |
* GNU General Public License for more details. |
14 |
* |
15 |
* You should have received a copy of the GNU General Public License |
16 |
* along with this program; if not, write to the Free Software |
17 |
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
18 |
* |
19 |
*/ |
20 |
#define RCSID "$Id: session.c,v 1.4 2004/01/10 18:15:36 mbuna Exp $" |
21 |
|
22 |
#ifdef HAVE_CONFIG_H |
23 |
#include "config.h" |
24 |
#endif |
25 |
|
26 |
#include "session.h" |
27 |
|
28 |
#include <peak/peak.h> |
29 |
|
30 |
#include <assert.h> |
31 |
#include <signal.h> |
32 |
#include <stdlib.h> |
33 |
#include <string.h> |
34 |
#include <time.h> |
35 |
#include <unistd.h> |
36 |
|
37 |
#include "cfgloader.h" |
38 |
#include "debug.h" |
39 |
#include "evreg.h" |
40 |
#include "irc_auth.h" |
41 |
#include "irc_init.h" |
42 |
#include "irc_network.h" /* irc_network_squit_downlink() */ |
43 |
#include "irc_parser.h" |
44 |
#include "irc_send.h" |
45 |
|
46 |
#include "scan.h" /* scan_init() */ |
47 |
|
48 |
peak_stream gIRCStream; /* IRC Stream reference - global */ |
49 |
|
50 |
time_t link_timestamp; |
51 |
|
52 |
static CHubLink *hubLink; |
53 |
static peak_timer timer_recon; |
54 |
|
55 |
#define LINK_STATUS_DISCONNECTED 0 |
56 |
#define LINK_STATUS_CONNECTED 1 |
57 |
#define LINK_STATUS_SQUITTED 2 |
58 |
static int link_status = LINK_STATUS_DISCONNECTED; |
59 |
|
60 |
static void session_init(void); |
61 |
static int session_try_hub(void); |
62 |
static int session_open(CHubLink *hublink); |
63 |
|
64 |
static void session_stream_event(peak_stream s, int type, void *context); |
65 |
static void session_stream_error(peak_stream s, int error_type, void *context); |
66 |
static void session_timer_recon(peak_timer ti, void *context); |
67 |
|
68 |
/* Initialize session module, create reconnect timer and interruptions |
69 |
* notification object for handling signals. |
70 |
*/ |
71 |
static void |
72 |
session_init() |
73 |
{ |
74 |
/* It's wise to use a reconnection timer for several reasons. We use it as a |
75 |
* starter too here (it will be called immediately when the task starts). |
76 |
*/ |
77 |
timer_recon = peak_timer_create(0, -1, session_timer_recon, NULL); |
78 |
peak_task_timer_add(peak_task_self(), timer_recon); |
79 |
} |
80 |
|
81 |
static int |
82 |
session_try_hub() |
83 |
{ |
84 |
int i; |
85 |
|
86 |
for (i = 0; i < gConfig->nhubs; i++) |
87 |
{ |
88 |
/* The first hub in the configuration file has got the highest priority |
89 |
*/ |
90 |
hubLink = cfgloader_next_hublink(hubLink); |
91 |
assert(hubLink != NULL); |
92 |
|
93 |
/* Try to establish connection */ |
94 |
if (session_open(hubLink) == 0) |
95 |
break; |
96 |
} |
97 |
cfgloader_retain_hublink(hubLink); /* Be sure we won't dispose this hub */ |
98 |
return 0; |
99 |
} |
100 |
|
101 |
static int |
102 |
session_open(CHubLink *hublink) |
103 |
{ |
104 |
struct sockaddr_in sin; |
105 |
|
106 |
Debug((DL_BASIC, "session_open")); |
107 |
|
108 |
memset(&sin, 0, sizeof(struct sockaddr_in)); |
109 |
sin.sin_family = AF_INET; |
110 |
sin.sin_addr = hublink->hub.address; |
111 |
sin.sin_port = htons((unsigned short)hublink->hub.port); |
112 |
|
113 |
/* Create socket stream */ |
114 |
gIRCStream = peak_stream_socket_create((struct sockaddr *)&sin, |
115 |
sizeof(sin), |
116 |
PEAK_STREAM_OPT_LINEMODE, |
117 |
session_stream_event, |
118 |
NULL); |
119 |
if (!gIRCStream) |
120 |
{ |
121 |
Debug((DL_BASIC, "session_open: peak_stream_socket_create failed!")); |
122 |
return -1; |
123 |
} |
124 |
|
125 |
if (hublink->hub.bind_address.s_addr != INADDR_ANY) |
126 |
{ |
127 |
struct sockaddr_in local_sin; |
128 |
memset(&local_sin, 0, sizeof(local_sin)); |
129 |
local_sin.sin_family = AF_INET; |
130 |
local_sin.sin_addr = hublink->hub.bind_address; |
131 |
local_sin.sin_port = htons(0); |
132 |
|
133 |
peak_stream_set_address(gIRCStream, (struct sockaddr *)&local_sin, |
134 |
sizeof(local_sin)); |
135 |
} |
136 |
|
137 |
peak_stream_set_buffered(gIRCStream, 1, MSGBUF_SIZE, |
138 |
gConfig->server.sendq, |
139 |
session_stream_error); |
140 |
|
141 |
/* Tell peak library that a connection should be established... */ |
142 |
if (peak_stream_connect(gIRCStream) != 0) |
143 |
{ |
144 |
Debug((DL_BASIC, "session_open: peak_stream_connect failed!")); |
145 |
peak_release(gIRCStream); |
146 |
return -1; |
147 |
} |
148 |
|
149 |
/* Schedule connection stream with our current task */ |
150 |
peak_stream_schedule(gIRCStream, peak_task_self()); |
151 |
return 0; |
152 |
} |
153 |
|
154 |
static void |
155 |
session_close() |
156 |
{ |
157 |
gIRCStream = NULL; |
158 |
|
159 |
irc_network_squit_downlink(); |
160 |
|
161 |
assert(irc_network_get_remote_server_count() == 0); |
162 |
|
163 |
peak_timer_configure(timer_recon, 30, -1); /* First, wait a bit. */ |
164 |
peak_task_timer_add(peak_task_self(), timer_recon); |
165 |
|
166 |
irc_reinit(); /* Then, reinit IRC modules */ |
167 |
evreg_finalize(); |
168 |
evreg_init(); |
169 |
} |
170 |
|
171 |
static void |
172 |
session_stream_event(peak_stream s, int type, void *context) |
173 |
{ |
174 |
switch (type) |
175 |
{ |
176 |
case PEAK_STREAM_EVT_OPEN: |
177 |
link_status = LINK_STATUS_CONNECTED; |
178 |
link_timestamp = peak_time(); |
179 |
irc_auth(hubLink->hub.password); |
180 |
break; |
181 |
case PEAK_STREAM_EVT_READ: |
182 |
if (link_status == LINK_STATUS_CONNECTED) |
183 |
irc_parser_parse_line(peak_stream_get_line(s)); |
184 |
break; |
185 |
case PEAK_STREAM_EVT_WRITE: |
186 |
/* In buffered mode, it means "write completed"... |
187 |
* Anyway we don't use it at all for now. |
188 |
*/ |
189 |
break; |
190 |
case PEAK_STREAM_EVT_END: |
191 |
Debug((DL_BASIC, "[EOF] end from server")); |
192 |
link_status = LINK_STATUS_DISCONNECTED; |
193 |
peak_release(s); |
194 |
session_close(); |
195 |
break; |
196 |
case PEAK_STREAM_EVT_ERROR: |
197 |
Debug((DL_BASIC, "[ERR] stream error with server")); |
198 |
link_status = LINK_STATUS_DISCONNECTED; |
199 |
peak_release(s); |
200 |
session_close(); |
201 |
break; |
202 |
default: |
203 |
fprintf(stderr, "type=%d\n", type); |
204 |
assert(0); |
205 |
break; |
206 |
} |
207 |
} |
208 |
|
209 |
static void |
210 |
session_stream_error(peak_stream s, int error_type, void *context) |
211 |
{ |
212 |
Debug((DL_BASIC, "session_stream_error: MAX SENDQ EXCEEDED (%d)", |
213 |
error_type)); |
214 |
if (link_status == LINK_STATUS_CONNECTED) |
215 |
{ |
216 |
send_squit("Max SendQ Exceeded"); |
217 |
link_status = LINK_STATUS_SQUITTED; |
218 |
peak_timer_configure(timer_recon, 5, -1); |
219 |
peak_task_timer_add(peak_task_self(), timer_recon); |
220 |
} |
221 |
} |
222 |
|
223 |
static void |
224 |
session_timer_recon(peak_timer ti, void *context) |
225 |
{ |
226 |
Debug((DL_BASIC, "session_recon: trying to reconnect pxyservd")); |
227 |
|
228 |
if (link_status == LINK_STATUS_SQUITTED) |
229 |
{ |
230 |
peak_stream_disconnect(gIRCStream); /* Enough! */ |
231 |
peak_timer_configure(timer_recon, 5, -1); /* Wait, again. */ |
232 |
return; |
233 |
} |
234 |
|
235 |
assert(link_status == LINK_STATUS_DISCONNECTED); |
236 |
|
237 |
session_try_hub(); |
238 |
peak_task_timer_remove(peak_task_self(), timer_recon); |
239 |
} |
240 |
|
241 |
/* Public methods */ |
242 |
void |
243 |
session_run(void) |
244 |
{ |
245 |
session_init(); /* Setup some things like auto reconnection timer */ |
246 |
evreg_init(); /* EVREG management */ |
247 |
irc_init(); /* Initialize IRC modules */ |
248 |
scan_init(); /* Initialize scan stuffs and PCKP/UDP server */ |
249 |
|
250 |
/* Run task event loop |
251 |
*/ |
252 |
Debug((DL_BASIC, "Running task...")); |
253 |
peak_task_run(peak_task_self()); |
254 |
Debug((DL_BASIC, "Exiting from peak_task_run")); |
255 |
} |
256 |
|
257 |
void |
258 |
session_reload(void) |
259 |
{ |
260 |
Debug((DL_BASIC, "session_cfg_reload: reloading configuration file...")); |
261 |
hubLink = NULL; /* reset hub list as it's gonna change */ |
262 |
|
263 |
/* TODO */ |
264 |
|
265 |
#if 0 |
266 |
scan_finalize(); |
267 |
scan_init(session_runloop); |
268 |
#endif |
269 |
} |
270 |
|
271 |
void |
272 |
session_stop(const char *message) |
273 |
{ |
274 |
Debug((DL_BASIC, "session_stop (%s)", message)); |
275 |
send_squit(message); /* can put in sendq but we don't care */ |
276 |
peak_task_break(peak_task_self()); |
277 |
} |