3 * Copyright (C) 2007 Tomas 'ZeXx86' Jedrzejek (zexx86@zexos.org)
4 * Copyright (C) 2008 Tomas 'ZeXx86' Jedrzejek (zexx86@zexos.org)
5 * Copyright (C) 2009 Tomas 'ZeXx86' Jedrzejek (zexx86@zexos.org)
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 3 of the License, or
10 * (at your option) any later version.
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.
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
27 #include <sys/socket.h>
29 #include <netinet/in.h>
30 #include <arpa/inet.h>
35 #define SUPPORT_IPV6 1
37 struct sockaddr
*sockName
; // "Jmeno" portu
38 struct sockaddr
*clientInfo
; // Klient, ktere se pripojil
40 int mainSocket
; // Soket
41 socklen_t addrlen
; // Velikost adresy vzdaleneho pocĂtace
42 char *buffer
; // Buffer
43 int client_count
; // Pocet pripojenych clientu
44 int proto
; // Protocol
49 int send_to_socket (int fd
, char *data
, unsigned len
)
52 if ((ret
= send (fd
, data
, len
, 0)) == -1) {
53 printf ("ERROR -> send () = -1\n");
60 int client_get (client_t
*c
)
63 c
->state
= CLIENT_STATE_TIMEOUT
;
67 memset (buffer
, 0, 1024);
68 int ret
= recv (c
->fd
, buffer
, 1024, 0);
77 // printf ("DATA: %s\n", buffer);
79 if (!strncmp (buffer
, "GET /", 5)) {
82 for (i
= 4; i
< ret
; i
++)
89 memcpy (c
->page
, buffer
+5, i
-5);
92 c
->state
= CLIENT_STATE_TRANSFER
;
96 printf ("ERROR -> corrupted http session ..\n");
98 c
->state
= CLIENT_STATE_DONE
;
103 client_t
*client_connected (int fd
)
106 for (c
= client_list
.next
; c
!= &client_list
; c
= c
->next
)
110 // alloc and init context
111 client_t
*ctx
= (client_t
*) malloc (sizeof (client_t
));
117 ctx
->state
= CLIENT_STATE_CONNECTED
;
120 ctx
->next
= &client_list
;
121 ctx
->prev
= client_list
.prev
;
122 ctx
->prev
->next
= ctx
;
123 ctx
->next
->prev
= ctx
;
128 int client_handle (client_t
*c
)
131 case CLIENT_STATE_CONNECTED
:
132 return client_get (c
);
133 case CLIENT_STATE_TRANSFER
:
134 return http_transfer (c
);
135 case CLIENT_STATE_DONE
:
136 case CLIENT_STATE_TIMEOUT
:
137 /* disconnect socket */
140 /* delete client_t * struct from list */
141 c
->next
->prev
= c
->prev
;
142 c
->prev
->next
= c
->next
;
151 int init (int port
, int flags
)
156 if (flags
& FLAG_IPV6
) {
158 printf ("> initializing IPv6\n");
160 printf ("> initializing IPv4\n");
162 if ((mainSocket
= socket (proto
, SOCK_STREAM
, IPPROTO_TCP
)) == -1) {
163 printf ("ERROR -> socket ()\n");
167 if (proto
== AF_INET6
) {
168 struct sockaddr_in6
*sockName6
= (struct sockaddr_in6
*) malloc (sizeof (struct sockaddr_in6
));
169 clientInfo
= (struct sockaddr
*) malloc (sizeof (struct sockaddr_in6
));
171 if (!sockName6
|| !clientInfo
)
174 sockName6
->sin6_family
= proto
;
175 sockName6
->sin6_port
= htons (port
);
176 //sockName6->sin6_addr.s6_addr = INADDR6_ANY;
178 sockName
= (struct sockaddr
*) sockName6
;
180 addrlen
= sizeof (struct sockaddr_in6
);
182 struct sockaddr_in
*sockName4
= (struct sockaddr_in
*) malloc (sizeof (struct sockaddr_in
));
183 clientInfo
= (struct sockaddr
*) malloc (sizeof (struct sockaddr_in
));
185 if (!sockName4
|| !clientInfo
)
188 sockName4
->sin_family
= proto
;
189 sockName4
->sin_port
= htons (port
);
190 sockName4
->sin_addr
.s_addr
= INADDR_ANY
;
192 sockName
= (struct sockaddr
*) sockName4
;
194 addrlen
= sizeof (struct sockaddr_in
);
197 if ((bind (mainSocket
, (struct sockaddr
*) sockName
, addrlen
)) == -1) {
198 printf ("ERROR -> bind () - %d\n", port
);
202 /* max 10 connecting clients */
203 if (listen (mainSocket
, 10) == -1) {
204 printf ("ERROR -> listen ()\n");
208 // Let's switch socket mode to non-blocking
209 int oldFlag
= fcntl (mainSocket
, F_GETFL
, 0);
210 if (fcntl (mainSocket
, F_SETFL
, oldFlag
| O_NONBLOCK
) == -1) {
211 printf ("ERROR -> fcntl ()\n");
215 printf ("> listen on port: %d\n", port
);
217 buffer
= (char *) malloc (sizeof (char) * 1025);
220 printf ("Buffer is out of memory\n");
224 client_list
.next
= &client_list
;
225 client_list
.prev
= &client_list
;
236 client
= accept (mainSocket
, (struct sockaddr
*) clientInfo
, &addrlen
);
241 if (proto
== AF_INET
) {
242 struct sockaddr_in
*clientInfoS
= (struct sockaddr_in
*) clientInfo
;
243 inet_ntop (proto
, (void *) &clientInfoS
->sin_addr
, str
, 40);
245 printf ("> New client (%d) -- %s:%d connected !\n", client
, str
, clientInfoS
->sin_port
);
246 } else if (proto
== AF_INET6
) {
247 struct sockaddr_in6
*clientInfoS
= (struct sockaddr_in6
*) clientInfo
;
248 inet_ntop (proto
, (void *) &clientInfoS
->sin6_addr
, str
, 40);
250 printf ("> New client (%d) -- [%s]:%d connected !\n", client
, str
, clientInfoS
->sin6_port
);
253 // Nastavime soket do neblokovaciho rezimu
254 int oldFlag
= fcntl (client
, F_GETFL
, 0);
255 if (fcntl (client
, F_SETFL
, oldFlag
| O_NONBLOCK
) == -1) {
256 printf ("Cant set socket to nonblocking mode\n");
260 client_t
*c
= client_connected (client
);
269 for (c
= client_list
.next
; c
!= &client_list
; c
= c
->next
) {
270 if (!client_handle (c
))