1 #include "config.h"
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <sys/types.h>
5 #include <sys/socket.h>
6 #include <netdb.h>
7 #include <netinet/in.h>
8 #include <arpa/inet.h>
9 #include <string.h>
10 #include <unistd.h>
11 #include "evpath.h"
12 #include "cm_internal.h"
13
14 #if defined (__INTEL_COMPILER)
15 // Allow int conversions
16 # pragma warning (disable: 2259)
17 #endif
18 static void socket_accept_thin_client(void *cmv, void * sockv);
19 extern void CMget_qual_hostname(CManager cm, char *buf, int len);
20
21 #ifndef SOCKET_ERROR
22 #define SOCKET_ERROR -1
23 #endif
24 extern void
25 CMget_port_range(CManager cm, int *high_bound, int *low_bound);
26
27 extern int
EVthin_socket_listen(CManager cm,char ** hostname_p,int * port_p)28 EVthin_socket_listen(CManager cm, char **hostname_p, int *port_p)
29 {
30
31 unsigned int length;
32 struct sockaddr_in sock_addr;
33 int sock_opt_val = 1;
34 int conn_sock;
35 int int_port_num = 0;
36 u_short port_num = 0;
37 char host_name[256];
38 int high_bound, low_bound;
39 CMget_port_range(cm, &high_bound, &low_bound);
40
41 conn_sock = socket(AF_INET, SOCK_STREAM, 0);
42 if (conn_sock == SOCKET_ERROR) {
43 fprintf(stderr, "Cannot open INET socket\n");
44 return 0;
45 }
46 sock_addr.sin_family = AF_INET;
47 sock_addr.sin_addr.s_addr = INADDR_ANY;
48 sock_addr.sin_port = (unsigned short) (htons(port_num));
49 if (setsockopt(conn_sock, SOL_SOCKET, SO_REUSEADDR, (char *) &sock_opt_val,
50 sizeof(sock_opt_val)) != 0) {
51 fprintf(stderr, "Failed to set 1REUSEADDR on INET socket\n");
52 return 0;
53 }
54 {
55 long seedval = time(NULL) + getpid();
56 /* port num is free. Constrain to range to standards */
57 int size = high_bound - low_bound;
58 int tries = 30;
59 int result = SOCKET_ERROR;
60 srand48(seedval);
61 while (tries > 0) {
62 int target = low_bound + size * drand48();
63 sock_addr.sin_port = htons(target);
64 CMtrace_out(cm, CMConnectionVerbose, "CMSocket trying to bind port %d", target);
65 result = bind(conn_sock, (struct sockaddr *) &sock_addr,
66 sizeof sock_addr);
67 int_port_num = target;
68 tries--;
69 if (result != SOCKET_ERROR) tries = 0;
70 if (tries%5 == 4) {
71 /* try reseeding in case we're in sync with another process */
72 srand48(time(NULL) + getpid());
73 }
74 if (tries == 20) {
75 /* damn, tried a lot, increase the range (This might violate specified range) */
76 size *= 10;
77 }
78 if (tries == 10) {
79 /* damn, tried a lot more, increase the range (This might violate specified range) */
80 size *= 10;
81 }
82 }
83 }
84 /* if (bind(conn_sock, (struct sockaddr *) &sock_addr,
85 sizeof sock_addr) == SOCKET_ERROR) {
86 fprintf(stderr, "Cannot bind INET socket\n");
87 return 0;
88 }*/
89 sock_opt_val = 1;
90 if (setsockopt(conn_sock, SOL_SOCKET, SO_REUSEADDR, (char *) &sock_opt_val,
91 sizeof(sock_opt_val)) != 0) {
92 perror("Failed to set 2REUSEADDR on INET socket");
93 return 0;
94 }
95 length = sizeof sock_addr;
96 if (getsockname(conn_sock, (struct sockaddr *) &sock_addr, &length) < 0) {
97 fprintf(stderr, "Cannot get socket name\n");
98 return 0;
99 }
100 /* begin listening for conns and set the backlog */
101 if (listen(conn_sock, FD_SETSIZE)) {
102 fprintf(stderr, "listen failed\n");
103 return 0;
104 }
105 /* set the port num as one we can be contacted at */
106
107 CM_fd_add_select(cm, conn_sock, socket_accept_thin_client,
108 (void *) cm, (void *) (long)conn_sock);
109
110
111 // int_port_num = (unsigned short)(ntohs(sock_addr.sin_port));
112
113 CMget_qual_hostname(cm, host_name, sizeof(host_name));
114
115 *hostname_p = strdup(host_name);
116 *port_p = int_port_num;
117 return 1;
118 }
119
120
121 typedef struct thin_conn {
122 FFSFile ffsfile;
123 int fd;
124 int target_stone;
125 int format_count;
126 FMStructDescList *format_list;
127 int max_src_list;
128 EVsource *src_list;
129 } *thin_conn_data;
130
thin_free_func(void * event_data,void * client_data)131 static void thin_free_func(void *event_data, void *client_data)
132 {
133 (void) client_data;
134 free(event_data);
135 }
136
137 static void
thin_data_available(void * cmv,void * conn_datav)138 thin_data_available(void *cmv, void * conn_datav)
139 {
140 thin_conn_data cd = conn_datav;
141 CManager cm = (CManager) cmv;
142 int i;
143
144 CManager_unlock(cm);
145 switch(FFSnext_record_type(cd->ffsfile)) {
146 case FFSindex:
147 break;
148 case FFSend:
149 case FFSerror:
150 close_FFSfile(cd->ffsfile);
151 free_FFSfile(cd->ffsfile);
152 for (i=0; i < cd->format_count; i++) {
153 int j = 0;
154 if (cd->format_list[i] == NULL) continue;
155 while((cd->format_list[i])[j].format_name != NULL) {
156 int k = 0;
157 free(cd->format_list[i][j].format_name);
158 while (cd->format_list[i][j].field_list[k].field_name != NULL) {
159 free((char*)cd->format_list[i][j].field_list[k].field_name);
160 free((char*)cd->format_list[i][j].field_list[k].field_type);
161 k++;
162 }
163 free(cd->format_list[i][j].field_list);
164 j++;
165 }
166 free(cd->format_list[i]);
167 }
168 free(cd->format_list);
169 for (i=0; i <= cd->max_src_list; i++) {
170 if (cd->src_list[i] != NULL) {
171 EVfree_source(cd->src_list[i]);
172 }
173 }
174 free(cd->src_list);
175 CM_fd_remove_select(cm, cd->fd);
176 free(cd);
177 break;
178 case FFSformat: {
179 FFSTypeHandle next_format = FFSread_format(cd->ffsfile);
180 FMStructDescList formats =
181 get_localized_formats(FMFormat_of_original(next_format));
182 FFSTypeHandle target =
183 FFSset_fixed_target(FFSContext_of_file(cd->ffsfile),
184 formats);
185 int format_num = FMformat_index(FMFormat_of_original(target));
186 if (cd->format_list == NULL) {
187 cd->format_list = malloc(sizeof(cd->format_list[0]));
188 cd->format_count = 1;
189 }
190 if (cd->format_count < format_num) {
191 cd->format_list =
192 realloc(cd->format_list,
193 (format_num + 1) * sizeof(cd->format_list[0]));
194 memset(cd->format_list + cd->format_count, 0,
195 sizeof(cd->format_list[0]) * (format_num -cd->format_count +1));
196 cd->format_count = format_num + 1;
197 }
198 cd->format_list[format_num] = formats;
199 break;
200 }
201 case FFSdata: {
202 FFSTypeHandle next_format = FFSnext_type_handle(cd->ffsfile);
203 int len = FFSnext_data_length(cd->ffsfile);
204 int format_num = FMformat_index(FMFormat_of_original(next_format));
205 void *data = malloc(len);
206 FFSread(cd->ffsfile, data);
207 if (cd->max_src_list < format_num) {
208 cd->src_list = realloc(cd->src_list,
209 (format_num+1) * sizeof(cd->src_list[0]));
210 memset(&cd->src_list[cd->max_src_list], 0,
211 (format_num - cd->max_src_list + 1) * sizeof(cd->src_list[0]));
212 cd->max_src_list = format_num;
213 }
214 if (cd->src_list[format_num] == NULL) {
215 cd->src_list[format_num] =
216 EVcreate_submit_handle_free(cm, cd->target_stone,
217 cd->format_list[format_num],
218 thin_free_func, cd);
219 }
220 EVsubmit(cd->src_list[format_num], data, NULL);
221 break;
222 }
223 case FFScomment: {
224 char *comment = FFSread_comment(cd->ffsfile);
225 if (strncmp(comment, "Stone ", 6) == 0) {
226 int tmp_stone;
227 if (sscanf(comment, "Stone %d", &tmp_stone) == 1) {
228 cd->target_stone = tmp_stone;
229 }
230 }
231 break;
232 }
233 }
234 CManager_lock(cm);
235 }
236
237 static void
socket_accept_thin_client(void * cmv,void * sockv)238 socket_accept_thin_client(void *cmv, void * sockv)
239 {
240 CManager cm = (CManager) cmv;
241 int conn_sock = (int) (long)sockv;
242 int sock;
243 struct sockaddr sock_addr;
244 unsigned int sock_len = sizeof(sock_addr);
245 int int_port_num;
246 struct linger linger_val;
247 int sock_opt_val = 1;
248 thin_conn_data cd;
249
250 #ifdef TCP_NODELAY
251 int delay_value = 1;
252 #endif
253
254 linger_val.l_onoff = 1;
255 linger_val.l_linger = 60;
256 if ((sock = accept(conn_sock, (struct sockaddr *) 0, (unsigned int *) 0)) == SOCKET_ERROR) {
257 perror("Cannot accept socket connection");
258 CM_fd_remove_select(cm, conn_sock);
259 fprintf(stderr, "failure in CMsockets removing socket connection\n");
260 return;
261 }
262 sock_opt_val = 1;
263 setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (char *) &sock_opt_val,
264 sizeof(sock_opt_val));
265 if (setsockopt(sock, SOL_SOCKET, SO_LINGER, (char *) &linger_val,
266 sizeof(struct linger)) != 0) {
267 perror("set SO_LINGER");
268 return;
269 }
270 #ifdef TCP_NODELAY
271 setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char *) &delay_value,
272 sizeof(delay_value));
273 #endif
274
275 sock_len = sizeof(sock_addr);
276 memset(&sock_addr, 0, sock_len);
277 getsockname(sock, (struct sockaddr *) &sock_addr, &sock_len);
278 int_port_num = (unsigned short) ntohs(((struct sockaddr_in *) &sock_addr)->sin_port);
279
280 memset(&sock_addr, 0, sizeof(sock_addr));
281 sock_len = sizeof(sock_addr);
282 if (getpeername(sock, &sock_addr,
283 &sock_len) == 0) {
284 int_port_num = (unsigned short) ntohs(((struct sockaddr_in *) &sock_addr)->sin_port);
285 }
286
287 (void) int_port_num;
288 cd = malloc(sizeof(*cd));
289 memset(cd, 0, sizeof(*cd));
290 cd->ffsfile = open_FFSfd((void*)(long)sock, "r");
291 cd->fd = sock;
292 cd->src_list = malloc(sizeof(cd->src_list[0]));
293 cd->src_list[0] = NULL;
294 INT_CM_fd_add_select(cm, sock,
295 (void (*)(void *, void *)) thin_data_available,
296 (void *) cm, (void *) cd);
297 }
298