added GPL header to all files and added INSTALL AUTHORS COPYING files.
[NeonServV5.git] / src / ClientSocket.c
1 /* ClientSocket.c - NeonServ v5.0
2  * Copyright (C) 2011  Philipp Kreil (pk910)
3  * 
4  * This program is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 3 of the License, or
7  * (at your option) any later version.
8  * 
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  * 
14  * You should have received a copy of the GNU General Public License 
15  * along with this program. If not, see <http://www.gnu.org/licenses/>. 
16  */
17
18 #include "ClientSocket.h"
19 #include "IRCParser.h"
20 #include "UserNode.h"
21
22 struct socket_list {
23     struct ClientSocket *data;
24     unsigned count;
25 };
26
27 //the magic list :P
28 static struct socket_list *sockets = NULL;
29 static char buffer[BUF_SIZ];
30
31 static void init_sockets() {
32     sockets = malloc(sizeof(*sockets));
33     if (!sockets)
34     {
35         perror("malloc() failed");
36         return;
37     }
38     sockets->data = NULL;
39     sockets->count = 0;
40 }
41
42 struct ClientSocket* create_socket(char *host, int port, char *pass, struct UserNode *user) {
43     if(sockets == NULL) init_sockets();
44     struct ClientSocket *client = malloc(sizeof(*client));
45     if (!client)
46     {
47         perror("malloc() failed");
48         return NULL;
49     }
50     client->host = strdup(host);
51     client->port = port;
52     printf("Connect: %s:%d\n", client->host, client->port);
53     client->pass = (pass == NULL ? NULL : strdup(pass));
54     client->user = user;
55     client->flags = 0;
56     client->bufferpos = 0;
57     client->traffic_in = 0;
58     client->traffic_out = 0;
59     client->connection_time = 0;
60         client->botid = 0;
61     client->clientid = 0;
62     client->next = sockets->data;
63     sockets->data = client;
64     return client;
65 }
66
67 #ifdef WIN32
68
69 int connect_socket(struct ClientSocket *client) {
70     if((client->flags & SOCKET_FLAG_CONNECTED)) return 1;
71     struct hostent *host;
72     struct sockaddr_in addr;
73     int sock;
74     addr.sin_addr.s_addr = inet_addr(client->host);
75     if (addr.sin_addr.s_addr == INADDR_NONE) {
76         host = gethostbyname(client->host);
77         if(!host) {
78             return SOCKET_ERROR;
79         }
80         memcpy(&(addr.sin_addr), host->h_addr_list[0], 4);
81     }
82     sock = socket(PF_INET, SOCK_STREAM, 0);
83     if (sock == -1)
84     {
85         perror("socket() failed");
86         return 0;
87     }
88
89     addr.sin_port = htons(client->port);
90     addr.sin_family = AF_INET;
91
92     if (connect(sock, (struct sockaddr*)&addr, sizeof(addr)) == -1)
93     {
94         perror("connect() failed");
95         return 0;
96     }
97
98     client->sock = sock;
99     client->flags |= SOCKET_FLAG_CONNECTED;
100     client->connection_time = time(0);
101
102     //send the IRC Headers
103     char sendBuf[512];
104     int len;
105
106     if(client->pass && strcmp(client->pass, "")) {
107         len = sprintf(sendBuf, "PASS :%s\n", client->pass);
108         write_socket(client, sendBuf, len);
109     }
110     len = sprintf(sendBuf, "USER %s 0 0 :%s\n", client->user->ident, client->user->realname);
111     write_socket(client, sendBuf, len);
112     len = sprintf(sendBuf, "NICK %s\n", client->user->nick);
113     write_socket(client, sendBuf, len);
114
115     return 1;
116 }
117
118 #else
119
120 int connect_socket(struct ClientSocket *client) {
121     if((client->flags & SOCKET_FLAG_CONNECTED)) return 1;
122     struct hostent *host;
123     struct sockaddr_in addr;
124     int sock;
125     if (!inet_aton(client->host, &addr.sin_addr))
126     {
127         host = gethostbyname(client->host);
128         if (!host)
129         {
130             perror("gethostbyname() failed");
131             return 0;
132         }
133         addr.sin_addr = *(struct in_addr*)host->h_addr;
134     }
135     sock = socket(PF_INET, SOCK_STREAM, 0);
136     if (sock == -1)
137     {
138         perror("socket() failed");
139         return 0;
140     }
141
142     addr.sin_port = htons(client->port);
143     addr.sin_family = AF_INET;
144
145     if (connect(sock, (struct sockaddr*)&addr, sizeof(addr)) == -1)
146     {
147         perror("connect() failed");
148         return 0;
149     }
150
151     client->sock = sock;
152     client->flags |= SOCKET_FLAG_CONNECTED;
153     client->connection_time = time(0);
154
155     //send the IRC Headers
156     char sendBuf[512];
157     int len;
158
159     if(client->pass) {
160         len = sprintf(sendBuf, "PASS :%s\n", client->pass);
161         write_socket(client, sendBuf, len);
162     }
163     len = sprintf(sendBuf, "USER %s 0 0 :%s\n", client->user->ident, client->user->realname);
164     write_socket(client, sendBuf, len);
165     len = sprintf(sendBuf, "NICK %s\n", client->user->nick);
166     write_socket(client, sendBuf, len);
167
168     return 1;
169 }
170
171 #endif
172
173 int close_socket(struct ClientSocket *client) {
174     if(client == NULL) return 0;
175     if((client->flags & SOCKET_FLAG_CONNECTED))
176         close(client->sock);
177     struct ClientSocket *sock, *last_sock = NULL;
178     for (sock = sockets->data; sock; sock = sock->next) {
179         if(sock == client) {
180             if(last_sock)
181                 last_sock->next = sock->next;
182             else
183                 sockets->data = sock->next;
184             sockets->count--;
185         } else
186             last_sock = sock;
187     }
188     free(client->host);
189     free(client->pass);
190     free(client);
191     return 1;
192 }
193
194 int write_socket(struct ClientSocket *client, char* msg, int len) {
195     if(!(client->flags & SOCKET_FLAG_CONNECTED)) return 0;
196     printf("[send %d] %s", len, msg);
197     #ifdef WIN32
198     send(client->sock, msg, len, 0);
199     #else
200     write(client->sock, msg, len);
201     #endif
202     client->traffic_out += len;
203     return 1;
204 }
205
206 void socket_loop(int timeout_seconds) {
207     if(sockets == NULL) return;
208     fd_set fds;
209     struct timeval timeout;
210     struct ClientSocket *sock;
211     int ret = 0, bytes, i;
212     
213     FD_ZERO(&fds);
214     for (sock = sockets->data; sock; sock = sock->next) {
215         if(!(sock->flags & SOCKET_FLAG_CONNECTED)) continue; //skip disconnected sockets
216         FD_SET(sock->sock, &fds);
217         if(sock->sock > ret)
218             ret = sock->sock;
219     }
220     timeout.tv_sec = timeout_seconds;
221     timeout.tv_usec = 0;
222     ret = select(ret + 1, &fds, NULL, NULL, &timeout);
223     if(ret == 0) return;
224     for (sock = sockets->data; sock; sock = sock->next) {
225         if((sock->flags & SOCKET_FLAG_CONNECTED) && FD_ISSET(sock->sock, &fds)) {
226             if(sock->bufferpos != 0) {
227                 #ifdef WIN32
228                 bytes = recv(sock->sock, buffer, sizeof(buffer), 0);
229                 #else
230                 bytes = read(sock->sock, buffer, sizeof(buffer));
231                 #endif
232                 if(bytes > 0) {
233                     for(i = 0; i < bytes; i++) {
234                         if(sock->bufferpos + i == BUF_SIZ*2) break; //buffer overflow
235                         sock->buffer[sock->bufferpos + i] = buffer[i];
236                     }
237                     sock->bufferpos += i;
238                 }
239             } else {
240                 #ifdef WIN32
241                 bytes = recv(sock->sock, sock->buffer, sizeof(sock->buffer), 0);
242                 #else
243                 bytes = read(sock->sock, sock->buffer, sizeof(sock->buffer));
244                 #endif
245                 if(bytes > 0)
246                     sock->bufferpos = bytes;
247             }
248             if(bytes <= 0) {
249                 //error
250                 sock->flags &= ~(SOCKET_FLAG_CONNECTED | SOCKET_FLAG_READY);
251                 bot_disconnect(sock);
252             } else {
253                 sock->traffic_in += bytes;
254                 int used = parse_lines(sock, sock->buffer, sock->bufferpos);
255                 if(used == sock->bufferpos + 1) {
256                     //used all bytes so just reset the bufferpos
257                     sock->bufferpos = 0;
258                 } else {
259                     for(i = 0; i < sock->bufferpos - used; i++) {
260                         sock->buffer[i] = sock->buffer[i+used];
261                     }
262                     sock->bufferpos -= used;
263                 }
264             }
265         }
266     }
267 }
268
269 void
270 putsock(struct ClientSocket *client, const char *text, ...)
271 {
272     va_list arg_list;
273     char sendBuf[MAXLEN];
274     int pos;
275     if (!(client->flags & SOCKET_FLAG_CONNECTED)) return;
276     sendBuf[0] = '\0';
277     va_start(arg_list, text);
278     pos = vsnprintf(sendBuf, MAXLEN - 2, text, arg_list);
279     va_end(arg_list);
280     if (pos < 0 || pos > (MAXLEN - 2)) pos = MAXLEN - 2;
281     sendBuf[pos] = '\n';
282     sendBuf[pos+1] = '\0';
283     write_socket(client, sendBuf, pos+1);
284 }
285
286 struct ClientSocket* getBots(int flags, struct ClientSocket* last_bot) {
287     struct ClientSocket *sock = (last_bot ? last_bot->next : sockets->data);
288     if(sock == NULL) return NULL;
289     for (; sock; sock = sock->next) {
290         if(!flags || (sock->flags & flags) == flags)
291             return sock;
292     }
293     return NULL;
294 }
295
296 void free_sockets() {
297     if(!sockets) return;
298     struct ClientSocket *client, *next;
299     for (client = sockets->data; client; client = next) {
300         next = client->next;
301         if((client->flags & SOCKET_FLAG_CONNECTED))
302             close(client->sock);
303         free(client->host);
304         free(client->pass);
305         free(client);
306     }
307     free(sockets);
308     sockets = NULL;
309 }