System call sys_getchar () was improved; stdin is correspond with 0. fd and stdout...
[ZeXOS.git] / apps / websrv / net.c
blob102ca5298cee57740c6e74641c1736cc72e20dc7
1 /*
2 * ZeX/OS
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/>.
22 #include <stdio.h>
23 #include <string.h>
24 #include <stdlib.h>
25 #include <unistd.h>
26 #include <fcntl.h>
27 #include <sys/socket.h>
28 #include <netdb.h>
29 #include <netinet/in.h>
30 #include <arpa/inet.h>
31 #include "http.h"
32 #include "client.h"
33 #include "net.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
46 client_t client_list;
49 int send_to_socket (int fd, char *data, unsigned len)
51 int ret;
52 if ((ret = send (fd, data, len, 0)) == -1) {
53 printf ("ERROR -> send () = -1\n");
54 return -1;
57 return ret;
60 int client_get (client_t *c)
62 if (c->ret > 32566) {
63 c->state = CLIENT_STATE_TIMEOUT;
64 return 1;
67 memset (buffer, 0, 1024);
68 int ret = recv (c->fd, buffer, 1024, 0);
70 if (ret < 1) {
71 c->ret ++;
72 return ret;
75 buffer[ret] = '\0';
77 //printf ("DATA: ");
78 //printf (buffer);
80 if (!strncmp (buffer, "GET / ", 6)) {
81 //while (ret > 0)
82 //ret = recv (c->fd, buffer, 1023, 0);
84 c->state = CLIENT_STATE_TRANSFER;
86 return 1;
89 c->state = CLIENT_STATE_DONE;
91 return ret;
94 client_t *client_connected (int fd)
96 client_t *c;
97 for (c = client_list.next; c != &client_list; c = c->next)
98 if (c->fd == fd)
99 return 0;
101 // alloc and init context
102 client_t *ctx = (client_t *) malloc (sizeof (client_t));
104 if (!ctx)
105 return 0;
107 ctx->fd = fd;
108 ctx->state = CLIENT_STATE_CONNECTED;
109 ctx->ret = 0;
111 ctx->next = &client_list;
112 ctx->prev = client_list.prev;
113 ctx->prev->next = ctx;
114 ctx->next->prev = ctx;
116 return ctx;
119 int client_handle (client_t *c)
121 switch (c->state) {
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 */
129 close (c->fd);
131 /* delete client_t * struct from list */
132 c->next->prev = c->prev;
133 c->prev->next = c->next;
135 free (c);
136 return 0;
139 return 0;
142 int init (int port, int flags)
144 proto = AF_INET;
146 /* switch to IPv6 */
147 if (flags & FLAG_IPV6) {
148 proto = AF_INET6;
149 printf ("> initializing IPv6\n");
150 } else
151 printf ("> initializing IPv4\n");
153 if ((mainSocket = socket (proto, SOCK_STREAM, IPPROTO_TCP)) == -1) {
154 printf ("ERROR -> socket ()\n");
155 return -1;
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");
162 return 0;
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)
170 return 0;
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);
179 } else {
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)
184 return 0;
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);
197 return -1;
200 /* max 10 connecting clients */
201 if (listen (mainSocket, 10) == -1) {
202 printf ("ERROR -> listen ()\n");
203 return -1;
206 printf ("> listen on port: %d\n", port);
208 buffer = (char *) malloc (sizeof (char) * 1025);
210 if (!buffer) {
211 printf ("Buffer is out of memory\n");
212 return 0;
215 client_list.next = &client_list;
216 client_list.prev = &client_list;
218 client_count = 0;
220 return http_init ();
223 int loop ()
225 int client = 0;
227 client = accept (mainSocket, (struct sockaddr *) clientInfo, &addrlen);
229 if (client > 0) {
230 char str[32];
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");
248 return 0;
251 client_t *c = client_connected (client);
253 if (!c)
254 close (client);
256 usleep (32);
260 client_t *c;
261 for (c = client_list.next; c != &client_list; c = c->next) {
262 if (!client_handle (c))
263 break;
266 return 1;