New developer version 0.6.8; added select () function; added demonstrating example...
[ZeXOS.git] / apps / mserver / main.c
blob262dbfb9c49218d06e7c28b115b8500fd9829563
1 /*
2 * ZeX/OS
3 * Copyright (C) 2010 Tomas 'ZeXx86' Jedrzejek (zexx86@zexos.org)
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include <fcntl.h>
21 #include <netdb.h>
22 #include <stdio.h>
23 #include <string.h>
24 #include <stdlib.h>
25 #include <unistd.h>
26 #include <arpa/inet.h>
27 #include <sys/socket.h>
28 #include <sys/select.h>
29 #include <netinet/in.h>
31 int fd;
32 fd_set myset;
33 struct sockaddr_in sockname;
35 /* Client structure */
36 typedef struct client_context {
37 struct client_context *next, *prev;
39 int fd;
40 } client_t;
42 client_t client_list;
44 int mserver_bind (int port)
46 if ((fd = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
47 printf ("> cant create socket\n");
48 return -1;
51 sockname.sin_family = AF_INET;
52 sockname.sin_port = htons (port);
54 // Create listen socket
55 if (bind (fd, (struct sockaddr *) &sockname, sizeof (sockname)) == -1) {
56 printf ("bind () - port is used\n");
57 return -1;
60 // Create queue for accept
61 if (listen (fd, 10) == -1) {
62 printf ("ERROR -> listen () == -1\n");
63 return -1;
66 client_list.next = &client_list;
67 client_list.prev = &client_list;
69 return 0;
72 int mserver_newclient ()
74 int client;
75 struct sockaddr_in clientInfo;
76 socklen_t addrlen = sizeof (clientInfo);
78 if (FD_ISSET (fd, &myset)) {
79 printf ("> new client connected\n");
81 client = accept (fd, (struct sockaddr *) &clientInfo, &addrlen);
83 if (client > 0) {
84 // alloc and init context
85 client_t *ctx = (client_t *) malloc (sizeof (client_t));
87 if (!ctx)
88 return 0;
90 ctx->fd = client;
92 ctx->next = &client_list;
93 ctx->prev = client_list.prev;
94 ctx->prev->next = ctx;
95 ctx->next->prev = ctx;
97 return 1;
101 return 0;
104 int mserver_sendtoall (client_t *me, char *buf, unsigned len)
106 if (!me)
107 return -1;
109 client_t *c;
110 for (c = client_list.next; c != &client_list; c = c->next)
111 if (c != me)
112 send (c->fd, buf, len, 0);
114 return 0;
117 int mserver_handle (client_t *c)
119 if (!FD_ISSET (c->fd, &myset))
120 return 0;
122 char str[80];
123 int r = recv (c->fd, str, 80, 0);
125 if (r > 0) {
126 str[r] = '\0';
128 printf ("data: %d: %s", c->fd, str);
129 mserver_sendtoall (c, str, r);
130 } else {
131 printf ("client %d is disconnected\n", c->fd);
132 /* disconnect socket */
133 close (c->fd);
135 /* delete client_t * struct from list */
136 c->next->prev = c->prev;
137 c->prev->next = c->next;
139 free (c);
140 return -1;
143 return 0;
146 int mserver_loop ()
148 struct timeval tv;
150 FD_ZERO (&myset);
151 FD_SET (fd, &myset);
153 client_t *c;
154 for (c = client_list.next; c != &client_list; c = c->next)
155 FD_SET (c->fd, &myset);
157 tv.tv_sec = 1;
158 tv.tv_usec = 0;
160 int ret = select (0, &myset, NULL, NULL, &tv);
162 if (ret == -1) {
163 printf ("select error\n");
164 return -1;
165 } else if (ret == 0) {
166 printf ("select timeout\n");
167 return -1;
170 /* check for incoming connections */
171 if (mserver_newclient ())
172 return 0;
174 for (c = client_list.next; c != &client_list; c = c->next) {
175 if (mserver_handle (c) == -1)
176 break;
179 return 0;
182 int main (int argc, char **argv)
184 int ret = mserver_bind (1234);
186 if (ret == -1)
187 return -1;
189 for (;; schedule ())
190 mserver_loop ();
192 return 0;