3 * Copyright (C) 2007 Tomas 'ZeXx86' Jedrzejek (zexx86@gmail.com)
4 * Copyright (C) 2008 Tomas 'ZeXx86' Jedrzejek (zexx86@gmail.com)
5 * Copyright (C) 2008 Tomas 'ZeXx86' Jedrzejek (zexx86@gmail.com)
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);
80 if (!strncmp (buffer
, "GET / ", 6)) {
82 //ret = recv (c->fd, buffer, 1023, 0);
84 c
->state
= CLIENT_STATE_TRANSFER
;
89 c
->state
= CLIENT_STATE_DONE
;
94 client_t
*client_connected (int fd
)
97 for (c
= client_list
.next
; c
!= &client_list
; c
= c
->next
)
101 // alloc and init context
102 client_t
*ctx
= (client_t
*) malloc (sizeof (client_t
));
108 ctx
->state
= CLIENT_STATE_CONNECTED
;
111 ctx
->next
= &client_list
;
112 ctx
->prev
= client_list
.prev
;
113 ctx
->prev
->next
= ctx
;
114 ctx
->next
->prev
= ctx
;
119 int client_handle (client_t
*c
)
122 case CLIENT_STATE_CONNECTED
:
123 return client_get (c
);
124 case CLIENT_STATE_TRANSFER
:
125 return http_transfer (c
);
126 case CLIENT_STATE_DONE
:
127 case CLIENT_STATE_TIMEOUT
:
128 /* disconnect socket */
131 /* delete client_t * struct from list */
132 c
->next
->prev
= c
->prev
;
133 c
->prev
->next
= c
->next
;
142 int init (int port
, int flags
)
147 if (flags
& FLAG_IPV6
) {
149 printf ("> initializing IPv6\n");
151 printf ("> initializing IPv4\n");
153 if ((mainSocket
= socket (proto
, SOCK_STREAM
, IPPROTO_TCP
)) == -1) {
154 printf ("ERROR -> socket ()\n");
158 // Let's switch socket mode to non-blocking
159 int oldFlag
= fcntl (mainSocket
, F_GETFL
, 0);
160 if (fcntl (mainSocket
, F_SETFL
, oldFlag
| O_NONBLOCK
) == -1) {
161 printf ("ERROR -> fcntl ()\n");
165 if (proto
== AF_INET6
) {
166 struct sockaddr_in6
*sockName6
= (struct sockaddr_in6
*) malloc (sizeof (struct sockaddr_in6
));
167 clientInfo
= (struct sockaddr
*) malloc (sizeof (struct sockaddr_in6
));
169 if (!sockName6
|| !clientInfo
)
172 sockName6
->sin6_family
= proto
;
173 sockName6
->sin6_port
= htons (port
);
174 //sockName6->sin6_addr.s6_addr = INADDR6_ANY;
176 sockName
= (struct sockaddr
*) sockName6
;
178 addrlen
= sizeof (sockName6
);
180 struct sockaddr_in
*sockName4
= (struct sockaddr_in
*) malloc (sizeof (struct sockaddr_in
));
181 clientInfo
= (struct sockaddr
*) malloc (sizeof (struct sockaddr_in
));
183 if (!sockName4
|| !clientInfo
)
186 sockName4
->sin_family
= proto
;
187 sockName4
->sin_port
= htons (port
);
188 sockName4
->sin_addr
.s_addr
= INADDR_ANY
;
190 sockName
= (struct sockaddr
*) sockName4
;
192 addrlen
= sizeof (sockName4
);
195 if (bind (mainSocket
, (struct sockaddr
*) sockName
, addrlen
) == -1) {
196 printf ("ERROR -> bind () - %d\n", port
);
200 /* max 10 connecting clients */
201 if (listen (mainSocket
, 10) == -1) {
202 printf ("ERROR -> listen ()\n");
206 printf ("> listen on port: %d\n", port
);
208 buffer
= (char *) malloc (sizeof (char) * 1025);
211 printf ("Buffer is out of memory\n");
215 client_list
.next
= &client_list
;
216 client_list
.prev
= &client_list
;
227 client
= accept (mainSocket
, (struct sockaddr
*) clientInfo
, &addrlen
);
232 if (proto
== AF_INET
) {
233 struct sockaddr_in
*clientInfoS
= (struct sockaddr_in
*) clientInfo
;
234 inet_ntop (proto
, (void *) &clientInfoS
->sin_addr
, str
, sizeof (clientInfoS
->sin_addr
));
236 printf ("> New client (%d) -- %s:%d connected !\n", client
, str
, clientInfoS
->sin_port
);
237 } else if (proto
== AF_INET6
) {
238 struct sockaddr_in6
*clientInfoS
= (struct sockaddr_in6
*) clientInfo
;
239 inet_ntop (proto
, (void *) &clientInfoS
->sin6_addr
, str
, sizeof (clientInfoS
->sin6_addr
));
241 printf ("> New client (%d) -- [%s]:%d connected !\n", client
, str
, clientInfoS
->sin6_port
);
244 // Nastavime soket do neblokovaciho rezimu
245 int oldFlag
= fcntl (client
, F_GETFL
, 0);
246 if (fcntl (client
, F_SETFL
, oldFlag
| O_NONBLOCK
) == -1) {
247 printf ("Cant set socket to nonblocking mode\n");
251 client_t
*c
= client_connected (client
);
261 for (c
= client_list
.next
; c
!= &client_list
; c
= c
->next
) {
262 if (!client_handle (c
))