1 |
/* |
2 |
* ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd). |
3 |
* packet.c: Packet handlers. |
4 |
* |
5 |
* Copyright (C) 2002 by the past and present ircd coders, and others. |
6 |
* |
7 |
* This program is free software; you can redistribute it and/or modify |
8 |
* it under the terms of the GNU General Public License as published by |
9 |
* the Free Software Foundation; either version 2 of the License, or |
10 |
* (at your option) any later version. |
11 |
* |
12 |
* This program is distributed in the hope that it will be useful, |
13 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
15 |
* GNU General Public License for more details. |
16 |
* |
17 |
* You should have received a copy of the GNU General Public License |
18 |
* along with this program; if not, write to the Free Software |
19 |
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 |
20 |
* USA |
21 |
* |
22 |
* $Id$ |
23 |
*/ |
24 |
#include "stdinc.h" |
25 |
#include "list.h" |
26 |
#include "ircd_defs.h" |
27 |
#include "s_bsd.h" |
28 |
#include "conf.h" |
29 |
#include "s_serv.h" |
30 |
#include "client.h" |
31 |
#include "ircd.h" |
32 |
#include "parse.h" |
33 |
#include "packet.h" |
34 |
#include "irc_string.h" |
35 |
#include "memory.h" |
36 |
#include "send.h" |
37 |
#include "s_misc.h" |
38 |
|
39 |
|
40 |
/** Add a certain number of bytes to a client's received statistics. |
41 |
* @param[in,out] client_p Client to update. |
42 |
* @param[in] length Number of newly received bytes to add. |
43 |
*/ |
44 |
static void |
45 |
update_bytes_received(struct Client *client_p, unsigned int length) |
46 |
{ |
47 |
client_p->localClient->recv.bytes += length; |
48 |
me.localClient->recv.bytes += length; |
49 |
} |
50 |
|
51 |
/** Add one message to a client's received statistics. |
52 |
* @param[in,out] client_p Client to update. |
53 |
*/ |
54 |
static void |
55 |
update_messages_received(struct Client *client_p) |
56 |
{ |
57 |
++me.localClient->recv.messages; |
58 |
++client_p->localClient->recv.messages; |
59 |
} |
60 |
|
61 |
/** Handle received data from a directly connected server. |
62 |
* @param[in] client_p Peer server that sent us data. |
63 |
* @param[in] buffer Input buffer. |
64 |
* @param[in] length Number of bytes in input buffer. |
65 |
* @return 1 on success or CPTR_KILLED if the client is squit. |
66 |
*/ |
67 |
int |
68 |
server_dopacket(struct Client *client_p, const char *buffer, int length) |
69 |
{ |
70 |
const char *src = NULL; |
71 |
char *endp = NULL; |
72 |
char *client_buffer = NULL; |
73 |
|
74 |
assert(client_p); |
75 |
|
76 |
update_bytes_received(client_p, length); |
77 |
|
78 |
client_buffer = client_p->localClient->buffer; |
79 |
endp = client_buffer + client_p->localClient->count; |
80 |
src = buffer; |
81 |
|
82 |
while (length-- > 0) |
83 |
{ |
84 |
*endp = *src++; |
85 |
|
86 |
/* |
87 |
* Yuck. Stuck. To make sure we stay backward compatible, |
88 |
* we must assume that either CR or LF terminates the message |
89 |
* and not CR-LF. By allowing CR or LF (alone) into the body |
90 |
* of messages, backward compatibility is lost and major |
91 |
* problems will arise. - Avalon |
92 |
*/ |
93 |
if (IsEol(*endp)) |
94 |
{ |
95 |
if (endp == client_buffer) |
96 |
continue; /* Skip extra LF/CR's */ |
97 |
*endp = '\0'; |
98 |
|
99 |
update_messages_received(client_p); |
100 |
|
101 |
if (parse(client_p, client_p->localClient->buffer, endp) == CPTR_KILLED) |
102 |
return CPTR_KILLED; |
103 |
|
104 |
/* |
105 |
* Socket is dead so exit |
106 |
*/ |
107 |
if (IsDead(client_p)) |
108 |
return exit_client(client_p, client_p, client_p->info); |
109 |
endp = client_buffer; |
110 |
} |
111 |
else if (endp < client_buffer + IRCD_BUFSIZE) |
112 |
++endp; /* There is always room for the null */ |
113 |
} |
114 |
|
115 |
client_p->localClient->count = endp - client_p->localClient->buffer; |
116 |
return 1; |
117 |
} |
118 |
|
119 |
/** Handle received data from a new (unregistered) connection. |
120 |
* @param[in] client_p Unregistered connection that sent us data. |
121 |
* @param[in] buffer Input buffer. |
122 |
* @param[in] length Number of bytes in input buffer. |
123 |
* @return 1 on success or CPTR_KILLED if the client is squit. |
124 |
*/ |
125 |
int |
126 |
connect_dopacket(struct Client *client_p, const char *buffer, int length) |
127 |
{ |
128 |
const char *src = NULL; |
129 |
char *endp = NULL; |
130 |
char *client_buffer = NULL; |
131 |
|
132 |
assert(client_p); |
133 |
|
134 |
update_bytes_received(client_p, length); |
135 |
|
136 |
client_buffer = client_p->localClient->buffer; |
137 |
endp = client_buffer + client_p->localClient->count; |
138 |
src = buffer; |
139 |
|
140 |
while (length-- > 0) |
141 |
{ |
142 |
*endp = *src++; |
143 |
|
144 |
/* |
145 |
* Yuck. Stuck. To make sure we stay backward compatible, |
146 |
* we must assume that either CR or LF terminates the message |
147 |
* and not CR-LF. By allowing CR or LF (alone) into the body |
148 |
* of messages, backward compatibility is lost and major |
149 |
* problems will arise. - Avalon |
150 |
*/ |
151 |
if (IsEol(*endp)) |
152 |
{ |
153 |
/* Skip extra LF/CR's */ |
154 |
if (endp == client_buffer) |
155 |
continue; |
156 |
*endp = '\0'; |
157 |
|
158 |
update_messages_received(client_p); |
159 |
|
160 |
if (parse(client_p, client_p->localClient->buffer, endp) == CPTR_KILLED) |
161 |
return CPTR_KILLED; |
162 |
if (IsDead(client_p)) |
163 |
return exit_client(client_p, client_p, client_p->info); /* Socket is dead so exit */ |
164 |
if (IsServer(client_p)) |
165 |
{ |
166 |
client_p->localClient->count = 0; |
167 |
return server_dopacket(client_p, src, length); |
168 |
} |
169 |
|
170 |
endp = client_buffer; |
171 |
} |
172 |
else if (endp < client_buffer + IRCD_BUFSIZE) |
173 |
++endp; /* There is always room for the null */ |
174 |
} |
175 |
|
176 |
client_p->localClient->count = endp - client_p->localClient->buffer; |
177 |
return 1; |
178 |
} |
179 |
|
180 |
/** Handle received data from a local client. |
181 |
* @param[in] client_p Local client that sent us data. |
182 |
* @param[in] length Total number of bytes in client's input buffer. |
183 |
* @return 1 on success or CPTR_KILLED if the client is squit. |
184 |
*/ |
185 |
int |
186 |
client_dopacket(struct Client *client_p, unsigned int length) |
187 |
{ |
188 |
assert(client_p); |
189 |
|
190 |
update_bytes_received(client_p, length); |
191 |
update_messages_received(client_p); |
192 |
|
193 |
if (parse(client_p, client_p->localClient->buffer, client_p->localClient->buffer + length) == CPTR_KILLED) |
194 |
return CPTR_KILLED; |
195 |
if (IsDead(client_p)) |
196 |
return exit_client(client_p, client_p, client_p->info); |
197 |
|
198 |
return 1; |
199 |
} |