4 * Copyright (C) 2004-2011 Simon Wunderlich <dotslash@packetmixer.de>
6 * This file is part of s3d, a 3d network display server.
7 * See http://s3d.berlios.de/ for more updates.
9 * s3d is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * s3d is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with s3d; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
26 #include <errno.h> /* errno */
27 #include <string.h> /* memset() */
28 #ifdef WIN32 /* sohn wars */
31 #include <sys/types.h> /* fd_set, FD*, socket, accept ... */
32 #include <sys/socket.h> /* socket, accept ... */
33 #include <sys/select.h> /* fd_set,FD* */
34 #include <sys/time.h> /* fd_set,FD* */
35 #include <netinet/in.h> /* ntohs(),htons(),htonl(),ntohl() */
36 #include <arpa/inet.h> /* network */
37 #endif /* sohn wars */
38 #include <time.h> /* select() timeval things */
39 #include <fcntl.h> /* fcntl(),F_SETOWN */
40 #ifndef F_SETOWN /* somehow it is not set with -ansi */
43 #include <unistd.h> /* read(),write(),getpid(),close() */
44 #include <stdlib.h> /* malloc(),free() */
47 static int tcp_sockid
;
52 struct sockaddr_in my_addr
;
53 s3dprintf(LOW
, "server: creating socket");
54 #ifdef WIN32 /* sohn wars */
56 if (WSAStartup(257, &datainfo
) != 0)
57 errnf("startup()", 0);
58 #endif /* auch sohn */
59 if ((tcp_sockid
= socket(AF_INET
, SOCK_STREAM
, 0)) < 0)
60 errnf("socket()", errno
);
62 s3dprintf(LOW
, "server: binding my local socket");
63 /* allow addresses to be reused */
64 /* this seems to have something to do with servers using one port */
65 if (setsockopt(tcp_sockid
, SOL_SOCKET
, SO_REUSEADDR
, &yes
, sizeof(int)) == -1)
66 errn("setsockopt(...,SO_REUSEADDR...)", errno
);
67 memset((char *)&my_addr
, 0, sizeof(my_addr
));
68 my_addr
.sin_family
= AF_INET
;
69 my_addr
.sin_port
= htons(S3D_PORT
);
70 my_addr
.sin_addr
.s_addr
= htons(INADDR_ANY
);
71 if (bind(tcp_sockid
, (struct sockaddr
*)&my_addr
, sizeof(my_addr
)) < 0)
72 errnf("bind()", errno
);
73 if (listen(tcp_sockid
, 5) < 0)
74 errnf("listen()", errno
);
76 if (fcntl(tcp_sockid
, F_SETFL
, O_ASYNC
| O_NONBLOCK
) < 0)
77 errnf("fcntl()", errno
);
78 if (fcntl(tcp_sockid
, F_SETOWN
, getpid()) < 0)
79 errnf("fcntl()", errno
);
94 /* watches the port for new connections */
95 int tcp_pollport(void)
97 fd_set fs_port
; /* filedescriptor set for listening port(s) */
98 int newsd
; /* new socket descriptor */
99 struct timeval tv
; /* time structure */
100 struct t_process
*new_p
; /* pointer to new process */
101 struct sockaddr client_addr
; /* new client's address */
102 socklen_t clilen
= sizeof(client_addr
); /* length of client's address */
105 FD_SET(tcp_sockid
, &fs_port
);
107 tv
.tv_sec
= tv
.tv_usec
= 0;
108 if (select(FD_SETSIZE
, &fs_port
, NULL
, NULL
, &tv
) < 0) {
109 if (errno
== EINTR
) { /* interruption by some evil signal, just do again :) */
110 errn("tcp_pollport():select()", errno
);
111 goto select_again
; /* oh no, a goto!! that's evil */
113 errn("tcp_pollport():select()", errno
);
114 } else if (FD_ISSET(tcp_sockid
, &fs_port
)) { /* redundant, I guess */
115 s3dprintf(HIGH
, "select(): new connection!!");
116 if ((newsd
= accept(tcp_sockid
, (struct sockaddr
*)&client_addr
, &clilen
)) < 0)
117 errn("accept()", errno
);
120 if (fcntl(newsd
, F_SETFL
, O_ASYNC
) < 0)
121 errnf("fcntl()", errno
);
122 if (fcntl(newsd
, F_SETOWN
, getpid()) < 0)
123 errnf("fcntl()", errno
);
125 new_p
= process_add();
126 new_p
->con_type
= CON_TCP
;
127 new_p
->sockid
= newsd
;
128 s3dprintf(HIGH
, "registered new connection %d as pid %d", new_p
->sockid
, new_p
->id
);
134 /* this is about looking for new data on the sockets */
135 /* returns 1 when there was new data. */
136 int tcp_pollproc(void)
138 fd_set fs_proc
; /* filedescriptor set for listening port(s) */
139 struct timeval tv
; /* time structure */
142 int i
, unfinished
, n
, off
;
148 for (i
= off
; i
< procs_n
; i
++) {
150 if (p
->con_type
== CON_TCP
) {
151 FD_SET(p
->sockid
, &fs_proc
);
153 if (n
>= FD_SETSIZE
) { /* don't overflow the setsize! */
160 /* maybe having a global fd_set for all the processes would have been better */
161 /* than generating them new in every poll. to be optimized... */
163 tv
.tv_sec
= tv
.tv_usec
= 0;
164 if (select(FD_SETSIZE
, &fs_proc
, NULL
, NULL
, &tv
) == -1) {
165 if (errno
== EINTR
) {
166 errn("tcp_pollproc():select()", errno
);
167 goto select_again_poll
;
169 errn("tcp_pollproc():select()", errno
);
172 /* data is available */
173 for (i
= 0; i
< procs_n
; i
++) {
175 if (p
->con_type
== CON_TCP
) {
176 if (FD_ISSET(p
->sockid
, &fs_proc
)) {
177 FD_CLR(p
->sockid
, &fs_proc
); /* clear it from the fd */
184 } while (unfinished
);
188 /* read some data from the line, pushes it into the buffer and calls prot_com_in */
189 int tcp_prot_com_in(struct t_process
*p
)
192 if (3 == tcp_readn(p
->sockid
, ibuf
, 3)) {
193 length
= ntohs(*((uint16_t *) ((uint8_t *) ibuf
+ 1)));
194 s3dprintf(VLOW
, "command %d, length %d", ibuf
[0], length
);
196 tcp_readn(p
->sockid
, ibuf
+ sizeof(int_least32_t), length
); /* uint16_t is limited to 65536, so */
197 /* length can't be bigger than that ... lucky */
199 prot_com_in(p
, ibuf
);
201 s3dprintf(LOW
, "tcp_prot_com_in():n_readn():fd seems to be dead (pid %d, sock %d)", p
->id
, p
->sockid
);
207 /* shamelessly ripped from simple ftp server */
208 int tcp_readn(int sock
, uint8_t * str
, int s
)
210 int no_left
, no_read
;
212 while (no_left
> 0) {
213 no_read
= read(sock
, str
, no_left
);
215 errn("read()", errno
);
226 int tcp_writen(int sock
, uint8_t * str
, int s
)
228 int no_left
, no_written
;
230 while (no_left
> 0) {
231 no_written
= write(sock
, str
, no_left
);
232 if (no_written
<= 0) {
233 errn("write()", errno
);
236 no_left
-= no_written
;
242 int tcp_remove(int sock
)