LCA2011 version
[tridge/junkcode.git] / sockbug.c
1 #include <stdio.h>
2 #include <sys/types.h>
3 #include <errno.h>
4 #include <fcntl.h>
5 #include <sys/socket.h>
6 #include <unistd.h>
7 #include <signal.h>
8 #include <errno.h>
9 #include <sys/stat.h>
10 #include <sys/wait.h>
11
12 /* work out what fcntl flag to use for non-blocking */
13 #ifdef O_NONBLOCK
14 # define NONBLOCK_FLAG O_NONBLOCK
15 #elif defined(SYSV)
16 # define NONBLOCK_FLAG O_NDELAY
17 #else 
18 # define NONBLOCK_FLAG FNDELAY
19 #endif
20
21 static int fdpair_pipe(int fd[2])
22 {
23         return pipe(fd);
24 }
25
26 static int fdpair_socketpair(int fd[2])
27 {
28         return socketpair(AF_UNIX, SOCK_STREAM, 0, fd);
29 }
30
31 /****************************************************************************
32 Set a fd into nonblocking mode.
33 ****************************************************************************/
34 static int set_nonblocking(int fd)
35 {
36         int val;
37
38         if((val = fcntl(fd, F_GETFL, 0)) == -1)
39                 return -1;
40         if (!(val & NONBLOCK_FLAG)) {
41                 val |= NONBLOCK_FLAG;
42                 fcntl(fd, F_SETFL, val);
43         }
44         return 0;
45 }
46
47 /****************************************************************************
48 Set a fd into blocking mode.
49 ****************************************************************************/
50 static int set_blocking(int fd)
51 {
52         int val;
53
54         if((val = fcntl(fd, F_GETFL, 0)) == -1)
55                 return -1;
56         if (val & NONBLOCK_FLAG) {
57                 val &= ~NONBLOCK_FLAG;
58                 fcntl(fd, F_SETFL, val);
59         }
60         return 0;
61 }
62
63 static int fdpair_tcp(int fd[2])
64 {
65         int listener;
66         struct sockaddr sock;
67         int socklen = sizeof(sock);
68         int len = socklen;
69         int one = 1;
70         int connect_done = 0;
71
72         fd[0] = fd[1] = listener = -1;
73
74         memset(&sock, 0, sizeof(sock));
75         
76         if ((listener = socket(PF_INET, SOCK_STREAM, 0)) == -1) goto failed;
77
78         setsockopt(listener,SOL_SOCKET,SO_REUSEADDR,(char *)&one,sizeof(one));
79
80         if (listen(listener, 1) != 0) goto failed;
81
82         if (getsockname(listener, &sock, &socklen) != 0) goto failed;
83
84         if ((fd[1] = socket(PF_INET, SOCK_STREAM, 0)) == -1) goto failed;
85
86         setsockopt(fd[1],SOL_SOCKET,SO_REUSEADDR,(char *)&one,sizeof(one));
87
88         set_nonblocking(fd[1]);
89
90         if (connect(fd[1],(struct sockaddr *)&sock,sizeof(sock)) == -1) {
91                 if (errno != EINPROGRESS) goto failed;
92         } else {
93                 connect_done = 1;
94         }
95
96         if ((fd[0] = accept(listener, &sock, &len)) == -1) goto failed;
97
98         setsockopt(fd[0],SOL_SOCKET,SO_REUSEADDR,(char *)&one,sizeof(one));
99
100         close(listener);
101         if (connect_done == 0) {
102                 if (connect(fd[1],(struct sockaddr *)&sock,sizeof(sock)) != 0) goto failed;
103         }
104
105         set_blocking(fd[1]);
106
107         /* all OK! */
108         return 0;
109
110  failed:
111         if (fd[0] != -1) close(fd[0]);
112         if (fd[1] != -1) close(fd[1]);
113         if (listener != -1) close(listener);
114         return -1;
115 }
116
117
118 static void testfn(char *name, int (*fn)(int fd[2]))
119 {
120         int dfile;
121         int fd[2];
122         char *fname = "sockbug.tmp";
123         int count;
124         pid_t pid;
125         char c = 'x';
126         struct stat st;
127         signal(SIGCHLD, SIG_IGN);
128
129         if (fn(fd) != 0) {
130                 perror(name);
131                 exit(1);
132         }
133
134         if ((pid=fork()) == 0) {
135                 /* we will put the data in a file as well as in the socketpair */
136                 dfile = open(fname, O_WRONLY|O_CREAT|O_TRUNC);
137                 if (dfile == -1) {
138                         perror(fname);
139                         exit(1);
140                 }
141         
142                 close(fd[0]);
143
144                 set_nonblocking(fd[1]);
145
146                 while (write(fd[1], &c, 1) == 1) 
147                         write(dfile, &c, 1);
148                 close(dfile);
149                 exit(1);
150         }
151
152         close(fd[1]);
153         waitpid(pid, NULL, 0);
154         
155         count=0;
156         while (read(fd[0], &c, 1) == 1) count++;
157
158         stat(fname, &st);
159         printf("%s: count was %d. Should have been %d\n", 
160                name, count, (int)st.st_size);
161
162         unlink(fname);
163 }
164
165 int main(int argc, char *argv[])
166 {
167         testfn("tcp", fdpair_tcp);
168         testfn("pipe", fdpair_pipe);
169         testfn("socketpair", fdpair_socketpair);
170         return 0;
171 }