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