]> git.sesse.net Git - jam/blob - jam.c
Generalize the file reading, and store the IPs in memory.
[jam] / jam.c
1 #include <stdio.h>
2 #include <string.h>
3 #include <stdlib.h>
4 #include <getopt.h>
5 #include <netdb.h>
6 #include <unistd.h>
7 #include <pthread.h>
8 #include <sys/socket.h>
9 #include <netinet/in.h>
10
11 unsigned short port = 2007;
12 struct in_addr *destinations = NULL;
13 unsigned num_destinations = 0;
14 unsigned room_destinations = 0;
15
16 const static struct option longopts[] = {
17         { "destination-file", required_argument, NULL, 'd' },
18         { "port", required_argument, NULL, 'p' },
19         { NULL, 0, NULL, 0 }
20 };
21
22 void read_ip_list(char *filename, struct in_addr **addr_list, unsigned *num, unsigned *room)
23 {
24         char buf[256];
25         FILE *in = fopen(filename, "r");
26         if (in == NULL) {
27                 perror(filename);
28                 exit(1);
29         }
30
31         for ( ;; ) {
32                 char *ptr;
33                 struct in_addr addr;
34                 struct hostent *he;
35
36                 if (fgets(buf, 256, in) == NULL)
37                         break;
38
39                 ptr = strchr(buf, '\n');
40                 if (ptr != NULL)
41                         *ptr = 0;
42
43                 ptr = strchr(buf, '\r');
44                 if (ptr != NULL)
45                         *ptr = 0;
46                 
47                 ptr = buf + strspn(buf, " \t");
48
49                 if (ptr[0] == '#' || ptr[0] == 0)
50                         continue;
51
52                 he = gethostbyname(ptr);
53                 if (he == NULL) {
54                         perror(ptr);
55                         exit(1);
56                 }
57
58                 // just pick the first for now
59                 memcpy(&addr.s_addr, he->h_addr_list[0], sizeof(addr.s_addr));
60
61                 if (*num >= *room) {
62                         if (*room == 0) {
63                                 *room = 16;
64                         } else {
65                                 *room <<= 1;
66                         }
67                         *addr_list = (struct in_addr *)realloc(*addr_list, *room * sizeof(struct in_addr));
68                 }
69
70                 (*addr_list)[*num] = addr;
71                 ++*num;
72         }
73
74         fclose(in);
75 }
76
77 void parse_options(int argc, char **argv)
78 {
79         int option_index = 0;
80
81         for ( ;; ) {
82                 int c = getopt_long(argc, argv, "d:p:", longopts, &option_index); 
83                 switch (c) {
84                 case 'd':
85                         read_ip_list(optarg, &destinations, &num_destinations, &room_destinations);
86                         break;
87                 case 'p':
88                         port = atoi(optarg);
89                         break;
90                 case -1:
91                         return;       // end of argument list
92                 default:
93                         fprintf(stderr, "Invalid option\n");
94                         exit(1);
95                 }
96         }
97 }
98
99 void *receiver_worker(void *arg)
100 {
101         int sock = (int)arg;
102         char buf[65536];
103
104         printf("Received worker for socket %u\n", sock);
105
106         for ( ;; ) {
107                 int ret = read(sock, buf, 65536);
108                 if (ret == 0)
109                         break;
110
111                 // FIXME: update stats here
112         }
113
114         printf("Socket %u done\n", sock);
115         
116         if (close(sock) == -1) {
117                 perror("close()");
118                 exit(1);
119         }
120
121         pthread_exit(0);
122 }
123
124 int get_server_socket(unsigned short port)
125 {
126         int server_sock;
127         struct sockaddr_in sin;
128         unsigned one = 1;
129
130         server_sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
131         if (server_sock == -1) {
132                 perror("socket()");
133                 exit(1);
134         }
135
136         if (setsockopt(server_sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) == -1) {
137                 perror("setsocket(SO_REUSEADDR)");
138                 exit(1);
139         }
140
141         sin.sin_family = AF_INET;
142         sin.sin_port = htons(port);
143         sin.sin_addr.s_addr = INADDR_ANY;
144
145         if (bind(server_sock, (struct sockaddr *)&sin, sizeof(struct sockaddr)) == -1) {
146                 perror("bind()");
147                 exit(1);
148         }
149
150         if (listen(server_sock, 255) == -1) {
151                 perror("listen()");
152                 exit(1);
153         }
154
155         return server_sock;
156 }
157
158 int main(int argc, char **argv)
159 {
160         int server_sock;
161
162         parse_options(argc, argv);
163         server_sock = get_server_socket(port);
164
165         // FIXME: fire off sender workers here
166
167         /*
168          * Listen for incoming connections, spawning off one receiver
169          * thread for each (which will just gobble up the data until
170          * we're done).
171          */
172         for ( ;; ) {
173                 struct sockaddr_in addr;
174                 socklen_t addr_len = sizeof(addr);
175                 pthread_t thread;
176                 pthread_attr_t attr;
177
178                 int sock = accept(server_sock, (struct sockaddr *)&addr, &addr_len);
179                 if (sock == -1) {
180                         perror("accept()");
181                         exit(1);
182                 }
183
184                 // FIXME: these do not really set errno
185                 if (pthread_attr_init(&attr) != 0) {
186                         perror("pthread_attr_init()");
187                         exit(1);
188                 }
189
190                 if (pthread_attr_setstacksize(&attr, PTHREAD_STACK_MIN + 65536 + 0x4000) != 0) {
191                         perror("pthread_attr_setstacksize");
192                         exit(1);
193                 }
194
195                 if (pthread_create(&thread, &attr, receiver_worker, (void *)sock) != 0) {
196                         perror("pthread_create()");
197                         exit(1);
198                 }
199         }
200
201         exit(0);
202 }