1 | /*********************************************************************** |
---|
2 | * |
---|
3 | * MP version 1.1.2: Multi Protocol |
---|
4 | * Kent State University, Kent, OH |
---|
5 | * Authors: S. Gray, N. Kajler, P. Wang |
---|
6 | * (C) 1993, 1994, 1995, 1996, 1997 All Rights Reserved |
---|
7 | * |
---|
8 | * NOTICE |
---|
9 | * |
---|
10 | * Permission to use, copy, modify, and distribute this software and |
---|
11 | * its documentation for non-commercial purposes and without fee is |
---|
12 | * hereby granted provided that the above copyright notice appear in all |
---|
13 | * copies and that both the copyright notice and this permission notice |
---|
14 | * appear in supporting documentation. |
---|
15 | * |
---|
16 | * Neither Kent State University nor the Authors make any representations |
---|
17 | * about the suitability of this software for any purpose. The MP Library |
---|
18 | * is distributed in the hope that it will be useful, but is provided "as |
---|
19 | * is" and without any warranty of any kind and without even the implied |
---|
20 | * warranty of merchantability or fitness for a particular purpose. |
---|
21 | * |
---|
22 | * |
---|
23 | * IMPLEMENTATION FILE: MP_TcpTransp.c |
---|
24 | * |
---|
25 | * Public interface routines to the "tcp" transport device. |
---|
26 | * These include read, write, open, close, and init routines. |
---|
27 | * There are some support routines as well. |
---|
28 | * |
---|
29 | * Change Log: |
---|
30 | * 08/16/96 hennig - tcp transport device ported to Windows95/NT |
---|
31 | * 11/25/95 sgray - added support to negotiate endian word order. |
---|
32 | * 11/20/95 sgray - added tcp_has_data() routine to determine |
---|
33 | * if there is any data on the link to read and |
---|
34 | * put it in the transp_op structure |
---|
35 | * 11/15/95 obachman - use vfork instead of fork |
---|
36 | * - major change to open_tcp_launch_mode: |
---|
37 | * 1.) -MPapplication takes one string: application |
---|
38 | * and its arguments |
---|
39 | * 2.) MP appends -MPhost -MPport to arguments of |
---|
40 | * application |
---|
41 | * 3.) rsh is started with -n to disable |
---|
42 | * standard input |
---|
43 | * 4.) rsh has fixed number of args, namely: |
---|
44 | * -n host application |
---|
45 | * 11/14/95 obachman - introduced macro for remote shell command |
---|
46 | * 11/10/95 obachman - cleaned up things around the select call, |
---|
47 | * so that it runs under Linux, and uses |
---|
48 | * the timestruct to actually come back after |
---|
49 | * an unsuccessful select |
---|
50 | * - fixed nasty bug on line 348: |
---|
51 | * tcp_rec->peerhost = (char *) malloc(sizeof(host) + 1); |
---|
52 | * should have been |
---|
53 | * tcp_rec->peerhost = (char *) malloc(strlen(host) + 1); |
---|
54 | * - similar in tcp_inti_transport |
---|
55 | * - one minor cast to (Char **) of dmy_args |
---|
56 | * September 11, 1995 SG - Reorganization of files. Cleaned up |
---|
57 | * header files and relocated source to |
---|
58 | * 3/3/96 sgray - moved call to tcp_init_transport() inside |
---|
59 | * tcp_open_transport() and removed the init |
---|
60 | * routine from the tcp_ops struct. |
---|
61 | * 5/16/96 sgray - Changed the tcp_read() routine to loop until it |
---|
62 | * has read all the data requested. This was done |
---|
63 | * b/c the higher level routines in the buffering |
---|
64 | * layer return failure if the number of bytes read |
---|
65 | * is not the number of bytes requested. We ran into |
---|
66 | * the problem that occasionally the application was |
---|
67 | * trying to read the data faster than the TCP layer |
---|
68 | * could provide it, providing a "false failure". |
---|
69 | * 3/11/97 sgray - Changed all memory management calls that allocate |
---|
70 | * or deallocate strings to use the "Raw" calls. |
---|
71 | * |
---|
72 | ***************************************************************************/ |
---|
73 | |
---|
74 | |
---|
75 | #ifndef lint |
---|
76 | static char vcid[] = "@(#) $Id: MP_TcpTransp.c,v 1.11 2001-11-05 17:11:11 Singular Exp $"; |
---|
77 | #endif /* lint */ |
---|
78 | |
---|
79 | #include "MP.h" |
---|
80 | #include <string.h> |
---|
81 | #include <stdlib.h> |
---|
82 | #include <signal.h> |
---|
83 | |
---|
84 | |
---|
85 | #ifdef __WIN32__ |
---|
86 | |
---|
87 | # include <process.h> |
---|
88 | |
---|
89 | #else /* not __WIN32__ */ |
---|
90 | |
---|
91 | |
---|
92 | #include <unistd.h> |
---|
93 | #include <netdb.h> |
---|
94 | |
---|
95 | #endif /* not __WIN32__ */ |
---|
96 | |
---|
97 | |
---|
98 | |
---|
99 | #define log_msg_len 128 |
---|
100 | #define MAX_ARGS 24 |
---|
101 | |
---|
102 | static char log_msg[log_msg_len]; /* for event logging */ |
---|
103 | |
---|
104 | |
---|
105 | static MP_Status_t tcp_negotiate_word_order _ANSI_ARGS_((MP_Link_pt)); |
---|
106 | static MP_Status_t tcp_negotiate_fp_format _ANSI_ARGS_((MP_Link_pt)); |
---|
107 | static MP_Status_t tcp_negotiate_bigint_format _ANSI_ARGS_((MP_Link_pt)); |
---|
108 | static MP_Status_t tcp_exchange_pids _ANSI_ARGS_((MP_Link_pt)); |
---|
109 | static int get_tcp_mode _ANSI_ARGS_((int, char**)); |
---|
110 | |
---|
111 | #ifdef __WIN32__ |
---|
112 | static int splitargs _ANSI_ARGS_((char*)); |
---|
113 | #endif |
---|
114 | |
---|
115 | |
---|
116 | MP_TranspOps_t tcp_ops = { |
---|
117 | tcp_write, |
---|
118 | tcp_read, |
---|
119 | tcp_flush, |
---|
120 | tcp_get_status, |
---|
121 | tcp_open_connection, |
---|
122 | tcp_close_connection, |
---|
123 | tcp_kill_connection |
---|
124 | }; |
---|
125 | |
---|
126 | |
---|
127 | /**** Private routines ******/ |
---|
128 | |
---|
129 | /*********************************************************************** |
---|
130 | * FUNCTION: get_tcp_mode |
---|
131 | * INPUT: argc - number of arguments in argv |
---|
132 | * argv - arguments as strings |
---|
133 | * OUTPUT: Success: one of MP_CONNECT_MODE, MP_LISTEN_MODE, MP_LAUNCH_MODE. |
---|
134 | * Failure: MP_NO_SUCH_TCP_MODE |
---|
135 | * OPERATION: Get the argument to the "-MPmode" option and see what it is. |
---|
136 | ***********************************************************************/ |
---|
137 | #ifdef __STDC__ |
---|
138 | static int get_tcp_mode(int argc, char **argv) |
---|
139 | #else |
---|
140 | static int get_tcp_mode(argc, argv) |
---|
141 | int argc; |
---|
142 | char **argv; |
---|
143 | #endif |
---|
144 | { |
---|
145 | char *cmode; |
---|
146 | |
---|
147 | #ifdef MP_DEBUG |
---|
148 | fprintf(stderr, "get_tcp_mode: entering\n"); |
---|
149 | fflush(stderr); |
---|
150 | #endif |
---|
151 | |
---|
152 | if ((cmode = IMP_GetCmdlineArg(argc, argv, "-MPmode")) != NULL) |
---|
153 | if (!strcmp(cmode, "connect")) |
---|
154 | return MP_CONNECT_MODE; |
---|
155 | else if (!strcmp(cmode, "listen")) |
---|
156 | return MP_LISTEN_MODE; |
---|
157 | else if (!strcmp(cmode, "launch")) |
---|
158 | return MP_LAUNCH_MODE; |
---|
159 | else if (!strcmp(cmode, "fork")) |
---|
160 | return MP_FORK_MODE; |
---|
161 | |
---|
162 | |
---|
163 | #ifdef MP_DEBUG |
---|
164 | fprintf(stderr, "get_tcp_mode: exiting\n"); |
---|
165 | fflush(stderr); |
---|
166 | #endif |
---|
167 | |
---|
168 | return MP_NO_SUCH_TCP_MODE; |
---|
169 | } |
---|
170 | |
---|
171 | |
---|
172 | /*********************************************************************** |
---|
173 | * FUNCTION: open_tcp_launch_mode |
---|
174 | * INPUT: link - pointer to link structure for this connection |
---|
175 | * argc - number of arguments in argv |
---|
176 | * argv - arguments as strings |
---|
177 | * OUTPUT: Success: MP_Success |
---|
178 | * socket connected to the specified host, port |
---|
179 | * Failure: MP_Failure |
---|
180 | * OPERATION: Launch an application remotely. rsh is used for this, |
---|
181 | * which isn't portable beyond Unix. The application name |
---|
182 | * must be supplied. First we open a port in listening mode, |
---|
183 | * then the application is launched with arguments asking it |
---|
184 | * to establish a connection to this host at the opened port. |
---|
185 | * Immediately after the launch, we do a blocking accept(), |
---|
186 | * waiting for the application to make the connection. |
---|
187 | * Unfortunately there may be problems, so maybe a non-blocking |
---|
188 | * accept would be better. |
---|
189 | * |
---|
190 | * Windows95/NT: Launching applications is only supported on |
---|
191 | * the local machine. This is done using the spawnv function. |
---|
192 | * If the "-MPhost <host>" option is given on the command line |
---|
193 | * <host> is first checked to see if it is identical to the |
---|
194 | * local host. |
---|
195 | ***********************************************************************/ |
---|
196 | |
---|
197 | /* Returns a dupliucate of string `str' in which string `replace_this' |
---|
198 | is replaced by string `replace_by_that' provided all strings are != |
---|
199 | NULL */ |
---|
200 | #ifdef __STDC__ |
---|
201 | static char* strdup_replace(const char* str, |
---|
202 | const char* replace_this, |
---|
203 | const char* replace_by_that) |
---|
204 | #else |
---|
205 | static char* strdup_replace(str, replace_this, replace_by_that) |
---|
206 | const char* str; |
---|
207 | const char* replace_this; |
---|
208 | const char* replace_by_that; |
---|
209 | #endif |
---|
210 | { |
---|
211 | char *sub, *ret; |
---|
212 | |
---|
213 | if (str == NULL) return NULL; |
---|
214 | |
---|
215 | if (replace_this != NULL && |
---|
216 | (sub = strstr(str, replace_this)) != NULL && |
---|
217 | replace_by_that != NULL) |
---|
218 | { |
---|
219 | ret = (char*) IMP_RawMemAllocFnc((strlen(str) |
---|
220 | + strlen(replace_by_that) - strlen(replace_this) |
---|
221 | + 1)*sizeof(char)); |
---|
222 | strcpy(ret, str); |
---|
223 | sprintf((void*) ret + ((void*) sub - (void*) str), |
---|
224 | "%s%s", replace_by_that, &sub[strlen(replace_this)]); |
---|
225 | } |
---|
226 | else |
---|
227 | { |
---|
228 | ret = IMP_RawMemAllocFnc((strlen(str) + 1)*sizeof(char)); |
---|
229 | strcpy(ret, str); |
---|
230 | } |
---|
231 | return ret; |
---|
232 | } |
---|
233 | |
---|
234 | #ifdef __STDC__ |
---|
235 | static int UsesLongOpt(int argc, char** argv, const char* opt) |
---|
236 | #else |
---|
237 | static int UsesLongOpt(argc, argv, opt) |
---|
238 | int argc; |
---|
239 | char** argv; |
---|
240 | const char* opt; |
---|
241 | #endif |
---|
242 | { |
---|
243 | int i=0; |
---|
244 | if (opt == NULL) return -1; |
---|
245 | |
---|
246 | while (i < argc && (argv[i][0] != '-' || strstr(argv[i], opt))) i++; |
---|
247 | |
---|
248 | if (i >= argc) return -1; |
---|
249 | if (argv[i][1] == '-') return 1; |
---|
250 | return 0; |
---|
251 | } |
---|
252 | |
---|
253 | #ifdef __STDC__ |
---|
254 | MP_Status_t open_tcp_launch_mode(MP_Link_pt link, |
---|
255 | int argc, |
---|
256 | char **argv) |
---|
257 | #else |
---|
258 | MP_Status_t open_tcp_launch_mode(link, argc, argv) |
---|
259 | MP_Link_pt link; |
---|
260 | int argc; |
---|
261 | char **argv; |
---|
262 | #endif |
---|
263 | { |
---|
264 | #ifdef __WIN32__ |
---|
265 | char myhost[64], cport[10]; |
---|
266 | char **dmy_args, **spawn_argv, *rhost, *p, *mpapp; |
---|
267 | int spawn_pid, i, applen, appopts; |
---|
268 | MP_TCP_t *tcp_rec; |
---|
269 | HOSTENT *myhostent, *rhostent; |
---|
270 | |
---|
271 | #ifdef MP_DEBUG |
---|
272 | fprintf(stderr, "open_tcp_launch_mode: entering\n"); |
---|
273 | fflush(stderr); |
---|
274 | #endif /* MP_DEBUG */ |
---|
275 | |
---|
276 | TEST_LINK_NULL(link); |
---|
277 | tcp_rec = (MP_TCP_t *)link->transp.private1; |
---|
278 | tcp_rec->peerhost = NULL; |
---|
279 | |
---|
280 | if (gethostname(myhost, 64) == SOCKET_ERROR) |
---|
281 | return MP_SetError(link, MP_Failure); |
---|
282 | |
---|
283 | /* |
---|
284 | * Let's assume that there is no rsh application available in Windows95/NT. |
---|
285 | * Therefore, all we can do is spawn a local process. So we must check if |
---|
286 | * the -MPhost argument is either equal to "localhost", myhost or not |
---|
287 | * specified at all. If not, we must bail out. |
---|
288 | */ |
---|
289 | rhost = IMP_GetCmdlineArg(argc, argv, "-MPhost"); |
---|
290 | if (rhost != NULL && strcmp(rhost, "localhost")) { |
---|
291 | |
---|
292 | /* |
---|
293 | * OK. So the user absolutely had to specify a host name. Then we have to |
---|
294 | * find out if myhost and the remote host are really the same machine. |
---|
295 | * |
---|
296 | * First, get host information for both host names. |
---|
297 | */ |
---|
298 | myhostent = gethostbyname(myhost); |
---|
299 | rhostent = gethostbyname(rhost); |
---|
300 | |
---|
301 | if (myhostent == NULL) { |
---|
302 | MP_LogEvent(link, MP_ERROR_EVENT, |
---|
303 | "MP_OpenLink: cannot get local host information."); |
---|
304 | return MP_SetError(link, MP_Failure); |
---|
305 | } |
---|
306 | |
---|
307 | if (rhostent == NULL) { |
---|
308 | MP_LogEvent(link, MP_ERROR_EVENT, |
---|
309 | "MP_OpenLink: cannot get remote host information."); |
---|
310 | return MP_SetError(link, MP_Failure); |
---|
311 | } |
---|
312 | |
---|
313 | /* Now compare both official host names and see if they are equal. */ |
---|
314 | if (strcmp(myhostent->h_name, rhostent->h_name)) { |
---|
315 | MP_LogEvent(link, MP_ERROR_EVENT, |
---|
316 | "MP_OpenLink: launching remote processes is not" |
---|
317 | "supported (yet)."); |
---|
318 | return MP_SetError(link, MP_Failure); |
---|
319 | } |
---|
320 | } |
---|
321 | |
---|
322 | /* Get the application to be launched. */ |
---|
323 | p = IMP_GetCmdlineArg(argc, argv, "-MPapplication"); |
---|
324 | if (p == NULL) { |
---|
325 | MP_LogEvent(link, MP_ERROR_EVENT, |
---|
326 | "MP_OpenLink: bad or missing -MPapplication argument"); |
---|
327 | return MP_SetError(link, MP_Failure); |
---|
328 | } |
---|
329 | |
---|
330 | /* |
---|
331 | * If we could execute an rsh application we could simply pass it the |
---|
332 | * -MPapplication argument string and let the rsh do the parsing. However, |
---|
333 | * as we need to use the spawnv function to launch the child process we must |
---|
334 | * split the application's argument string into the argv's ourselves: |
---|
335 | */ |
---|
336 | |
---|
337 | /* Make a copy of the -MPapplication argument string. */ |
---|
338 | applen = strlen(p) + 1; |
---|
339 | mpapp = (char*)IMP_RawMemAllocFnc(applen); |
---|
340 | if (mpapp == NULL) { |
---|
341 | MP_LogEvent(link, MP_ERROR_EVENT, |
---|
342 | "MP_OpenLink: memory allocation error"); |
---|
343 | return MP_SetError(link, MP_MemAlloc); |
---|
344 | } |
---|
345 | strcpy(mpapp, p); |
---|
346 | |
---|
347 | /* Split the argument string into several Null-terminated strings. */ |
---|
348 | appopts = splitargs(mpapp); |
---|
349 | |
---|
350 | /* Allocate memory for the application's argv array. */ |
---|
351 | spawn_argv = (char**)IMP_MemAllocFnc((appopts + 9) * sizeof(char*)); |
---|
352 | if (spawn_argv == NULL) { |
---|
353 | MP_LogEvent(link, MP_ERROR_EVENT, |
---|
354 | "MP_OpenLink: memory allocation error"); |
---|
355 | return MP_SetError(link, MP_MemAlloc); |
---|
356 | } |
---|
357 | |
---|
358 | /* Fill the argv array with pointers to the arguments. */ |
---|
359 | p = mpapp; |
---|
360 | for (i = 0; i < appopts; i++) { |
---|
361 | /* Take one argument and put it to the argv's. */ |
---|
362 | spawn_argv[i] = p; |
---|
363 | /* Advance the pointer to the next argument. */ |
---|
364 | while (*p++); |
---|
365 | } |
---|
366 | |
---|
367 | /* User shouldn't have specified a -MPport option, but we'll use it if |
---|
368 | it is there. */ |
---|
369 | if (IMP_GetCmdlineArg(argc, argv, "-MPport") == NULL) { |
---|
370 | dmy_args = (char**)IMP_MemAllocFnc((argc + 2) * sizeof(char *)); |
---|
371 | if (dmy_args == NULL) { |
---|
372 | MP_LogEvent(link, MP_ERROR_EVENT, |
---|
373 | "MP_OpenLink: memory allocation error"); |
---|
374 | return MP_SetError(link, MP_MemAlloc); |
---|
375 | } |
---|
376 | |
---|
377 | for (i = 0; i < argc; i++) |
---|
378 | dmy_args[i] = argv[i]; |
---|
379 | dmy_args[i++] = "-MPport"; |
---|
380 | dmy_args[i++] = MP_INIT_PORT; |
---|
381 | |
---|
382 | if (open_tcp_listen_mode(link, i, dmy_args) != MP_Success) { |
---|
383 | MP_LogEvent(link, MP_ERROR_EVENT, |
---|
384 | "MP_OpenLink: can't open a listening socket"); |
---|
385 | return MP_SetError(link, MP_CantConnect); |
---|
386 | } |
---|
387 | |
---|
388 | IMP_MemFreeFnc(dmy_args, (argc + 2) * sizeof(char*)); |
---|
389 | } |
---|
390 | |
---|
391 | else /* User specified port number, so we use original argc/argv pair. */ |
---|
392 | if (open_tcp_listen_mode(link, argc, argv) != MP_Success) { |
---|
393 | MP_LogEvent(link, MP_ERROR_EVENT, |
---|
394 | "MP_OpenLink: can't open a listening socket"); |
---|
395 | return MP_SetError(link, MP_CantConnect); |
---|
396 | } |
---|
397 | |
---|
398 | sprintf(cport, "%hd", tcp_rec->peerport); |
---|
399 | |
---|
400 | /* Add the remaining MP options to the application's argument list. */ |
---|
401 | spawn_argv[appopts ] = "-MPtransp"; |
---|
402 | spawn_argv[appopts+1] = "TCP"; |
---|
403 | spawn_argv[appopts+2] = "-MPmode"; |
---|
404 | spawn_argv[appopts+3] = "connect"; |
---|
405 | spawn_argv[appopts+4] = "-MPhost"; |
---|
406 | spawn_argv[appopts+5] = myhost; |
---|
407 | spawn_argv[appopts+6] = "-MPport"; |
---|
408 | spawn_argv[appopts+7] = cport; |
---|
409 | spawn_argv[appopts+8] = NULL; |
---|
410 | |
---|
411 | /* Launch the application. */ |
---|
412 | spawn_pid = spawnv(P_NOWAIT, spawn_argv[0], spawn_argv); |
---|
413 | if (spawn_pid == -1) { |
---|
414 | MP_LogEvent(link, MP_ERROR_EVENT, |
---|
415 | "MP_OpenLink: can't launch application"); |
---|
416 | return MP_SetError(link, MP_Failure); |
---|
417 | } |
---|
418 | |
---|
419 | /* Free the application argument memory. */ |
---|
420 | IMP_MemFreeFnc(spawn_argv, (appopts + 9) * sizeof(char*)); |
---|
421 | IMP_RawMemFreeFnc(mpapp); |
---|
422 | |
---|
423 | /* Wait for the child application to connect. */ |
---|
424 | socket_accept_blocking(link, &tcp_rec->sock); |
---|
425 | |
---|
426 | #ifdef MP_DEBUG |
---|
427 | fprintf(stderr, "open_tcp_launch_mode: exiting\n"); |
---|
428 | fflush(stderr); |
---|
429 | #endif |
---|
430 | |
---|
431 | RETURN_OK(link); |
---|
432 | |
---|
433 | #else /* not __WIN32__ */ |
---|
434 | |
---|
435 | char *rsh_argv[5], myhost[64], cport[5], **dmy_args, *appstr, *sub; |
---|
436 | int rsh_pid = -1, i; |
---|
437 | MP_TCP_t *tcp_rec; |
---|
438 | MP_Boolean_t localhost = MP_FALSE; |
---|
439 | |
---|
440 | #if defined(HAVE_GETHOSTBYNAME) && defined(RSH_CAN_LOCALHOST) |
---|
441 | if (gethostbyname("localhost") != NULL) localhost = MP_TRUE; |
---|
442 | #endif |
---|
443 | |
---|
444 | |
---|
445 | #ifdef MP_DEBUG |
---|
446 | fprintf(stderr, "open_tcp_launch_mode: entering\n"); |
---|
447 | fflush(stderr); |
---|
448 | #endif |
---|
449 | |
---|
450 | TEST_LINK_NULL(link); |
---|
451 | tcp_rec = (MP_TCP_t *)link->transp.private1; |
---|
452 | tcp_rec->peerhost = NULL; |
---|
453 | |
---|
454 | if (gethostname(myhost, 64) == -1) |
---|
455 | return MP_SetError(link, MP_Failure); |
---|
456 | |
---|
457 | /* NOTE: Ultrix doesn't like this order. It expects rsh host [-n] |
---|
458 | command. */ |
---|
459 | /* I tried on every platform I know using all the rsh commands |
---|
460 | available, and |
---|
461 | |
---|
462 | $rsh hostname -n command |
---|
463 | |
---|
464 | worked everywhere */ |
---|
465 | |
---|
466 | rsh_argv[0] = IMP_GetCmdlineArg(argc, argv, "-MPrsh"); |
---|
467 | if (rsh_argv[0] == NULL) |
---|
468 | rsh_argv[0] = MP_RSH_COMMAND; |
---|
469 | tcp_rec->rsh = IMP_StrDup(rsh_argv[0]); |
---|
470 | |
---|
471 | rsh_argv[1] = IMP_GetCmdlineArg(argc, argv, "-MPhost"); |
---|
472 | /* Let's not be too strict, and allow an empty -MPhost argument */ |
---|
473 | if (localhost) |
---|
474 | { |
---|
475 | if ((rsh_argv[1] != NULL && (strcmp(rsh_argv[1], myhost) == 0)) || |
---|
476 | rsh_argv[1] == NULL) |
---|
477 | rsh_argv[1] = "localhost"; |
---|
478 | } |
---|
479 | else |
---|
480 | { |
---|
481 | rsh_argv[1] = myhost; |
---|
482 | } |
---|
483 | rsh_argv[2] = "-n"; |
---|
484 | rsh_argv[3] = IMP_GetCmdlineArg(argc, argv, "-MPapplication"); |
---|
485 | if (rsh_argv[3] == NULL) { |
---|
486 | MP_LogEvent(link, MP_ERROR_EVENT, |
---|
487 | "MP_OpenLink: bad or missing -MPapplication argument"); |
---|
488 | return MP_SetError(link, MP_Failure); |
---|
489 | } |
---|
490 | |
---|
491 | /* |
---|
492 | * User shouldn't have specified a -MPport option, but we'll use it if |
---|
493 | * it is there. |
---|
494 | */ |
---|
495 | |
---|
496 | if (IMP_GetCmdlineArg(argc, argv, "-MPport") == NULL) { |
---|
497 | dmy_args = (char**)IMP_MemAllocFnc((argc + 2) * sizeof(char*)); |
---|
498 | if (dmy_args == NULL) { |
---|
499 | MP_LogEvent(link, MP_ERROR_EVENT, |
---|
500 | "MP_OpenLink: memory allocation error"); |
---|
501 | return MP_SetError(link, MP_MemAlloc); |
---|
502 | } |
---|
503 | |
---|
504 | for (i = 0; i < argc; i++) |
---|
505 | dmy_args[i] = argv[i]; |
---|
506 | dmy_args[i++] = "-MPport"; |
---|
507 | dmy_args[i++] = MP_INIT_PORT; |
---|
508 | |
---|
509 | if (open_tcp_listen_mode(link, i, dmy_args) != MP_Success) { |
---|
510 | MP_LogEvent(link, MP_ERROR_EVENT, |
---|
511 | "MP_OpenLink: can't open a listening socket"); |
---|
512 | return MP_SetError(link, MP_CantConnect); |
---|
513 | } |
---|
514 | |
---|
515 | IMP_MemFreeFnc(dmy_args, (argc + 2) * sizeof(char *)); |
---|
516 | } |
---|
517 | |
---|
518 | else |
---|
519 | /* User specified port number, so we use original argc/argv pair. */ |
---|
520 | if (open_tcp_listen_mode(link, argc, argv) != MP_Success) { |
---|
521 | MP_LogEvent(link, MP_ERROR_EVENT, |
---|
522 | "MP_OpenLink: can't open a listening socket"); |
---|
523 | return MP_SetError(link, MP_CantConnect); |
---|
524 | } |
---|
525 | |
---|
526 | sprintf(cport, "%hd", tcp_rec->peerport); |
---|
527 | if (localhost && |
---|
528 | (strcmp(rsh_argv[1], myhost) == 0 || |
---|
529 | strcmp(rsh_argv[1], "localhost") == 0)) |
---|
530 | sprintf(myhost, "localhost"); |
---|
531 | |
---|
532 | if (strstr(rsh_argv[3], "$MPport") != NULL || |
---|
533 | strstr(rsh_argv[3], "$MPhost") != NULL) |
---|
534 | { |
---|
535 | sub = strdup_replace(rsh_argv[3], "$MPport", cport); |
---|
536 | appstr = strdup_replace(sub, "$MPhost", myhost); |
---|
537 | IMP_RawMemFreeFnc(sub); |
---|
538 | } |
---|
539 | else |
---|
540 | { |
---|
541 | appstr = (char*)IMP_RawMemAllocFnc(strlen(rsh_argv[3]) + 110); |
---|
542 | strcpy(appstr, rsh_argv[3]); |
---|
543 | |
---|
544 | if (UsesLongOpt(argc, argv, "MPapplication") > 0) |
---|
545 | { |
---|
546 | strcat(appstr, " --MPtransp TCP --MPmode connect --MPhost "); |
---|
547 | strcat(appstr, myhost); |
---|
548 | strcat(appstr, " --MPport "); |
---|
549 | strcat(appstr, cport); |
---|
550 | } |
---|
551 | else |
---|
552 | { |
---|
553 | strcat(appstr, " -MPtransp TCP -MPmode connect -MPhost "); |
---|
554 | strcat(appstr, myhost); |
---|
555 | strcat(appstr, " -MPport "); |
---|
556 | strcat(appstr, cport); |
---|
557 | } |
---|
558 | |
---|
559 | } |
---|
560 | |
---|
561 | rsh_argv[3] = appstr; |
---|
562 | rsh_argv[4] = NULL; |
---|
563 | if (tcp_rec->peerhost == NULL) |
---|
564 | tcp_rec->peerhost = IMP_StrDup(rsh_argv[1]); |
---|
565 | |
---|
566 | if ((rsh_pid = vfork()) == -1) { |
---|
567 | MP_LogEvent(link, MP_ERROR_EVENT, |
---|
568 | "MP_OpenLink: can't fork to launch application"); |
---|
569 | return MP_SetError(link, MP_Failure); |
---|
570 | } |
---|
571 | |
---|
572 | if (!rsh_pid) { |
---|
573 | execvp(rsh_argv[0], rsh_argv); |
---|
574 | fputs("open_tcp_launch_mode: execvp failed - bailing out\n", stderr); |
---|
575 | fflush(stderr); |
---|
576 | _exit(1); |
---|
577 | } |
---|
578 | |
---|
579 | socket_accept_blocking(link, &tcp_rec->sock); |
---|
580 | |
---|
581 | IMP_RawMemFreeFnc(appstr); |
---|
582 | |
---|
583 | #ifdef MP_DEBUG |
---|
584 | fprintf(stderr, "open_tcp_launch_mode: exiting\n"); |
---|
585 | fflush(stderr); |
---|
586 | #endif |
---|
587 | |
---|
588 | RETURN_OK(link); |
---|
589 | #endif /* not __WIN32__ */ |
---|
590 | } |
---|
591 | |
---|
592 | |
---|
593 | |
---|
594 | /*********************************************************************** |
---|
595 | * FUNCTION: open_tcp_listen_mode |
---|
596 | * INPUT: link - pointer to link structure for this connection |
---|
597 | * argc - number of arguments in argv |
---|
598 | * argv - arguments as strings |
---|
599 | * OUTPUT: Success: MP_Success |
---|
600 | * socket connected to the specified host, port |
---|
601 | * Failure: MP_Failure |
---|
602 | * OPERATION: Open a socket in the AF_INET domain, verify that the port |
---|
603 | * is in the legal range (don't annoy anyone), bind the socket, |
---|
604 | * finally, do a listen. We update the link structure with |
---|
605 | * the socket and port information. |
---|
606 | ***********************************************************************/ |
---|
607 | #ifdef __STDC__ |
---|
608 | MP_Status_t open_tcp_listen_mode(MP_Link_pt link, |
---|
609 | int argc, |
---|
610 | char **argv) |
---|
611 | #else |
---|
612 | MP_Status_t open_tcp_listen_mode(link, argc, argv) |
---|
613 | MP_Link_pt link; |
---|
614 | int argc; |
---|
615 | char **argv; |
---|
616 | #endif |
---|
617 | { |
---|
618 | SOCKADDR_IN isin; |
---|
619 | SOCKET sock; |
---|
620 | int attempts = 0; |
---|
621 | char *cport; |
---|
622 | short port; |
---|
623 | MP_TCP_t *tcp_rec = (MP_TCP_t *)link->transp.private1; |
---|
624 | |
---|
625 | #ifdef MP_DEBUG |
---|
626 | fprintf(stderr, "open_tcp_listen_mode: entering\n"); |
---|
627 | fflush(stderr); |
---|
628 | #endif /* MP_DEBUG */ |
---|
629 | |
---|
630 | tcp_rec->peerhost = NULL; |
---|
631 | |
---|
632 | if ((cport = IMP_GetCmdlineArg(argc, argv, "-MPport")) == NULL) |
---|
633 | return MP_SetError(link, MP_Failure); |
---|
634 | |
---|
635 | port = atoi(cport); |
---|
636 | if (port < IPPORT_RESERVED) |
---|
637 | port = IPPORT_RESERVED; |
---|
638 | |
---|
639 | sock = socket(AF_INET, SOCK_STREAM, 0); |
---|
640 | if (sock == INVALID_SOCKET) { |
---|
641 | sprintf(log_msg, |
---|
642 | "open_tcp_listen_mode: " |
---|
643 | "Cannot open stream socket (socket error %d)", |
---|
644 | LASTERROR); |
---|
645 | MP_LogEvent(link, MP_ERROR_EVENT, log_msg); |
---|
646 | return MP_SetError(link, MP_Failure); |
---|
647 | } |
---|
648 | |
---|
649 | /* Initialize socket's address structure */ |
---|
650 | isin.sin_family = AF_INET; |
---|
651 | isin.sin_addr.s_addr = htonl(INADDR_ANY); |
---|
652 | isin.sin_port = htons(port); |
---|
653 | |
---|
654 | while (bind(sock, (SOCKADDR*)&isin, sizeof(isin)) == SOCKET_ERROR) { |
---|
655 | if (LASTERROR == ERRORCODE(EADDRINUSE)) { |
---|
656 | port++; |
---|
657 | |
---|
658 | /* since port is an unsigned short, it may wrap around */ |
---|
659 | if (port < IPPORT_RESERVED) |
---|
660 | port = IPPORT_RESERVED; |
---|
661 | |
---|
662 | isin.sin_port = htons(port); |
---|
663 | attempts = 0; |
---|
664 | } |
---|
665 | |
---|
666 | if (attempts++ > MP_MAX_BIND_ATTEMPTS) { |
---|
667 | MP_LogEvent(link, MP_ERROR_EVENT, |
---|
668 | "open_tcp_listen_mode: Cannot bind"); |
---|
669 | return MP_SetError(link, MP_Failure); |
---|
670 | } |
---|
671 | } |
---|
672 | |
---|
673 | /* Now listen for the anticipated connect request */ |
---|
674 | listen(sock, 1); |
---|
675 | tcp_rec->bindsock = sock; |
---|
676 | tcp_rec->sock = sock; |
---|
677 | tcp_rec->peerport = port; |
---|
678 | |
---|
679 | #ifndef NO_LOGGING |
---|
680 | if (link->logmask & MP_LOG_INIT_EVENTS) { |
---|
681 | sprintf(log_msg, |
---|
682 | "open_tcp_listen_mode: socket -> %d, port -> %d", |
---|
683 | sock, port); |
---|
684 | MP_LogEvent(link, MP_INIT_EVENT, log_msg); |
---|
685 | } |
---|
686 | #endif /* NO_LOGGING */ |
---|
687 | |
---|
688 | #ifdef MP_DEBUG |
---|
689 | fprintf(stderr, "\t tcp_rec->sock = %d\n", tcp_rec->sock); |
---|
690 | fprintf(stderr, "\t tcp_rec->port = %d\n", tcp_rec->peerport); |
---|
691 | fprintf(stderr, |
---|
692 | "open_tcp_listen_mode: exiting - socket = %d, port = %d\n", |
---|
693 | sock, port); |
---|
694 | fflush(stderr); |
---|
695 | #endif |
---|
696 | |
---|
697 | RETURN_OK(link); |
---|
698 | } |
---|
699 | |
---|
700 | |
---|
701 | |
---|
702 | /*********************************************************************** |
---|
703 | * FUNCTION: open_tcp_fork_mode |
---|
704 | * INPUT: link - pointer to link structure for this connection |
---|
705 | * OUTPUT: Success: MP_Success |
---|
706 | * socket connected to the a forked child |
---|
707 | * Failure: MP_Failure - couldn't make the connection. |
---|
708 | * OPERATION: forks a child, establishes a connection to it and uses |
---|
709 | * the return of the fork to set parent/child attribute |
---|
710 | ***********************************************************************/ |
---|
711 | #ifdef __STDC__ |
---|
712 | MP_Status_t open_tcp_fork_mode(MP_Link_pt link, int argc, char** argv) |
---|
713 | #else |
---|
714 | MP_Status_t open_tcp_fork_mode(link, argc, argv) |
---|
715 | MP_Link_pt link; |
---|
716 | int argc; |
---|
717 | char** argv; |
---|
718 | #endif |
---|
719 | { |
---|
720 | int pid; |
---|
721 | MP_TCP_t *tcp_rec = (MP_TCP_t *) link->transp.private1; |
---|
722 | #ifndef NO_LOGGING |
---|
723 | char log_msg[200]; |
---|
724 | char *parent_logfilename = link->env->logfilename; |
---|
725 | FILE *parent_logfd = link->env->logfd; |
---|
726 | #endif |
---|
727 | |
---|
728 | /* prepare the socket */ |
---|
729 | if (open_tcp_listen_mode(link, argc, argv) != MP_Success) |
---|
730 | { |
---|
731 | MP_LogEvent(link, MP_ERROR_EVENT, |
---|
732 | "MP_OpenLink: can't open a listening socket"); |
---|
733 | return MP_SetError(link, MP_CantConnect); |
---|
734 | } |
---|
735 | |
---|
736 | #ifndef NO_LOGGING |
---|
737 | /* Open the log file before the fork, so that the processes do not |
---|
738 | get out of sync */ |
---|
739 | sprintf(log_msg, |
---|
740 | "open_tcp_fork: Preparing to create fork link, parent id: %d", |
---|
741 | getpid()); |
---|
742 | if (open_logfile(link->env) != MP_Success) return MP_Failure; |
---|
743 | MP_LogEvent(link, MP_INIT_EVENT, |
---|
744 | "open_tcp_fork: MP Log file for a forked (child) link"); |
---|
745 | sprintf(log_msg, "open_tcp_fork: Parent link: L%d, logfile: %s, pid: %d", |
---|
746 | link->link_id, parent_logfilename, getpid()); |
---|
747 | MP_LogEvent(link, MP_INIT_EVENT, log_msg); |
---|
748 | #endif |
---|
749 | |
---|
750 | /* Do the fork */ |
---|
751 | if ((pid = fork()) == -1) |
---|
752 | { |
---|
753 | #ifndef NO_LOGGING |
---|
754 | link->env->logfilename = parent_logfilename; |
---|
755 | link->env->logfd = parent_logfd; |
---|
756 | #endif |
---|
757 | MP_LogEvent(link, MP_ERROR_EVENT, "MP_OpenLink: can't fork"); |
---|
758 | return MP_SetError(link, MP_Failure); |
---|
759 | } |
---|
760 | |
---|
761 | if (!pid) |
---|
762 | { |
---|
763 | /* Child's business */ |
---|
764 | MP_Status_t stat; |
---|
765 | char cport[12]; |
---|
766 | char *argv[] = {"MPtransp","TCP","-MPmode","connect","-MPhost", |
---|
767 | "localhost", "-MPport", ""}; |
---|
768 | sprintf(cport,"%d",tcp_rec->peerport); |
---|
769 | argv[7] = cport; |
---|
770 | |
---|
771 | /* establish connection */ |
---|
772 | stat = open_tcp_connect_mode(link, 8, argv); |
---|
773 | |
---|
774 | #ifndef NO_LOGGING |
---|
775 | IMP_RawMemFreeFnc(parent_logfilename); |
---|
776 | if (stat == MP_Success) |
---|
777 | sprintf(log_msg, "open_tcp_fork: opened forked link, child id: %d", |
---|
778 | getpid()); |
---|
779 | else |
---|
780 | sprintf(log_msg, |
---|
781 | "open_tcp_fork: open of forked link failed, child is exited"); |
---|
782 | MP_LogEvent(link, MP_ERROR_EVENT, log_msg); |
---|
783 | #endif |
---|
784 | if (stat != MP_Success) |
---|
785 | _exit(1); |
---|
786 | else |
---|
787 | { |
---|
788 | tcp_rec->status = MP_LinkIsChild; |
---|
789 | return MP_Success; |
---|
790 | } |
---|
791 | } |
---|
792 | else |
---|
793 | { |
---|
794 | /* parent's business */ |
---|
795 | #ifndef NO_LOGGING |
---|
796 | /* reset logging stuff */ |
---|
797 | link->env->logfilename = parent_logfilename; |
---|
798 | link->env->logfd = parent_logfd; |
---|
799 | #endif |
---|
800 | |
---|
801 | /* establish connection */ |
---|
802 | socket_accept_blocking(link, &tcp_rec->sock); |
---|
803 | tcp_rec->status = MP_LinkIsParent; |
---|
804 | |
---|
805 | #ifndef NO_LOGGING |
---|
806 | sprintf(log_msg,"open_tcp_fork: opened fork link, parent id: %d", |
---|
807 | getpid()); |
---|
808 | MP_LogEvent(link, MP_INIT_EVENT, log_msg); |
---|
809 | #endif |
---|
810 | |
---|
811 | RETURN_OK(link); |
---|
812 | } |
---|
813 | } |
---|
814 | |
---|
815 | /*********************************************************************** |
---|
816 | * FUNCTION: open_tcp_connect_mode |
---|
817 | * INPUT: link - pointer to link structure for this connection |
---|
818 | * argc - number of arguments in argv |
---|
819 | * argv - arguments as strings |
---|
820 | * OUTPUT: Success: MP_Success |
---|
821 | * socket connected to the specified host, port |
---|
822 | * Failure: MP_Failure - couldn't make the connection. |
---|
823 | * Maybe the peer isn't listening. |
---|
824 | * OPERATION: Establish a TCP connection to the peer's port. Update the |
---|
825 | * private tcp structure accordingly. We hope that there |
---|
826 | * is a peer actually listening on the given port. We make |
---|
827 | * 1000 attempts before giving up. |
---|
828 | ***********************************************************************/ |
---|
829 | #ifdef __STDC__ |
---|
830 | MP_Status_t open_tcp_connect_mode(MP_Link_pt link, |
---|
831 | int argc, |
---|
832 | char **argv) |
---|
833 | #else |
---|
834 | MP_Status_t open_tcp_connect_mode(link, argc, argv) |
---|
835 | MP_Link_pt link; |
---|
836 | int argc; |
---|
837 | char **argv; |
---|
838 | #endif |
---|
839 | { |
---|
840 | SOCKET sock; |
---|
841 | int attempts = 0; |
---|
842 | HOSTENT *hp; |
---|
843 | SOCKADDR_IN isin; |
---|
844 | char *host, *cport, *ptr; |
---|
845 | short port; |
---|
846 | MP_TCP_t *tcp_rec = (MP_TCP_t *)link->transp.private1; |
---|
847 | |
---|
848 | #ifdef MP_DEBUG |
---|
849 | fprintf(stderr, "open_tcp_connect_mode: entering\n"); |
---|
850 | fflush(stderr); |
---|
851 | #endif /* MP_DEBUG */ |
---|
852 | |
---|
853 | tcp_rec->peerhost = NULL; |
---|
854 | |
---|
855 | /* get the port number */ |
---|
856 | if ( |
---|
857 | (cport = IMP_GetCmdlineArg(argc, argv, "-MPport")) == NULL) |
---|
858 | return MP_SetError(link, MP_Failure); |
---|
859 | |
---|
860 | port = (short) strtol(cport, &ptr, 10); |
---|
861 | if ((host = IMP_GetCmdlineArg(argc, argv, "-MPhost")) == NULL) |
---|
862 | host = link->env->thishost; |
---|
863 | |
---|
864 | if (ptr == cport || errno == ERANGE) |
---|
865 | return MP_SetError(link, MP_Failure); |
---|
866 | |
---|
867 | if ((hp = gethostbyname(host)) == NULL) { |
---|
868 | MP_LogEvent(link, MP_ERROR_EVENT, |
---|
869 | "open_tcp_connect_mode - cannot get hostname"); |
---|
870 | return MP_SetError(link, MP_Failure); |
---|
871 | } |
---|
872 | |
---|
873 | sock = socket(AF_INET, SOCK_STREAM, 0); |
---|
874 | if (sock == INVALID_SOCKET) { |
---|
875 | sprintf(log_msg, |
---|
876 | "open_tcp_connect_mode - Cannot open socket (socket error %d)", |
---|
877 | LASTERROR); |
---|
878 | MP_LogEvent(link, MP_ERROR_EVENT, log_msg); |
---|
879 | return MP_SetError(link, MP_Failure); |
---|
880 | } |
---|
881 | |
---|
882 | /* Initialize the socket address to the server's address. */ |
---|
883 | memset((char *)&isin, 0, sizeof(isin)); |
---|
884 | isin.sin_family = AF_INET; |
---|
885 | memcpy(&isin.sin_addr.s_addr, hp->h_addr, hp->h_length); |
---|
886 | isin.sin_port = htons(port); |
---|
887 | |
---|
888 | /* Connect to the server. */ |
---|
889 | while (connect(sock, (SOCKADDR*)&isin, sizeof(isin)) == SOCKET_ERROR) { |
---|
890 | CLOSE_SOCKET(sock); |
---|
891 | if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) { |
---|
892 | sprintf(log_msg, |
---|
893 | "open_tcp_connect_mode " |
---|
894 | "- Cannot open socket (socket error %d)", LASTERROR); |
---|
895 | MP_LogEvent(link, MP_ERROR_EVENT, log_msg); |
---|
896 | return MP_SetError(link, MP_Failure); |
---|
897 | } |
---|
898 | |
---|
899 | if (attempts > MP_MAX_BIND_ATTEMPTS) { |
---|
900 | MP_LogEvent(link, MP_ERROR_EVENT, |
---|
901 | "open_tcp_connect_mode - Cannot connect"); |
---|
902 | return MP_SetError(link, MP_Failure); |
---|
903 | } |
---|
904 | |
---|
905 | attempts++; |
---|
906 | } |
---|
907 | |
---|
908 | if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char*)&sock, sizeof(sock)) |
---|
909 | == SOCKET_ERROR) { |
---|
910 | sprintf(log_msg, |
---|
911 | "open_tcp_connect_mode " |
---|
912 | "- cannot set socket option (socket error %d)", LASTERROR); |
---|
913 | MP_LogEvent(link, MP_ERROR_EVENT, log_msg); |
---|
914 | return MP_SetError(link, MP_Failure); |
---|
915 | } |
---|
916 | |
---|
917 | tcp_rec->bindsock = INVALID_SOCKET; |
---|
918 | tcp_rec->sock = sock; |
---|
919 | tcp_rec->peerport = port; |
---|
920 | |
---|
921 | tcp_rec->peerhost = (char*)IMP_RawMemAllocFnc(strlen(host) +1); |
---|
922 | TEST_MEM_ALLOC_ERROR(link, tcp_rec->peerhost); |
---|
923 | strcpy(tcp_rec->peerhost, host); |
---|
924 | |
---|
925 | tcp_rec->myhost = (char*)IMP_RawMemAllocFnc(MP_HOST_NAME_LEN); |
---|
926 | TEST_MEM_ALLOC_ERROR(link, tcp_rec->myhost); |
---|
927 | if (gethostname(tcp_rec->myhost, MP_HOST_NAME_LEN) == SOCKET_ERROR) { |
---|
928 | IMP_RawMemFreeFnc(tcp_rec->peerhost); |
---|
929 | IMP_RawMemFreeFnc(tcp_rec->myhost); |
---|
930 | tcp_rec->myhost = NULL; |
---|
931 | } |
---|
932 | |
---|
933 | #ifdef MP_DEBUG |
---|
934 | fprintf(stderr, "open_tcp_connect_mode: exiting - socket is %d\n", sock); |
---|
935 | fflush(stderr); |
---|
936 | #endif |
---|
937 | |
---|
938 | RETURN_OK(link); |
---|
939 | } |
---|
940 | |
---|
941 | |
---|
942 | |
---|
943 | /*********************************************************************** |
---|
944 | * FUNCTION: socket_accept_non_blocking |
---|
945 | * INPUT: sock - the socket to do the accept on |
---|
946 | * OUTPUT: Success: the socket to be used for io |
---|
947 | * Failure: MP_Failure |
---|
948 | * sock contains the socket number of the accepted |
---|
949 | * socket. |
---|
950 | * PURPOSE: Perform a non-blocking accept. If we timeout before getting |
---|
951 | * a connection request, return MP_Failure. |
---|
952 | ***********************************************************************/ |
---|
953 | #ifdef __STDC__ |
---|
954 | MP_Status_t socket_accept_non_blocking(MP_Link_pt link, SOCKET *sock) |
---|
955 | #else |
---|
956 | MP_Status_t socket_accept_non_blocking(link, sock) |
---|
957 | MP_Link_pt link; |
---|
958 | SOCKET *sock; |
---|
959 | #endif |
---|
960 | { |
---|
961 | SOCKADDR addr; |
---|
962 | SOCKET nsock = 0; |
---|
963 | int attempts, addrlen = sizeof(addr); |
---|
964 | fd_set read_template; |
---|
965 | TIMEVAL timeout; |
---|
966 | |
---|
967 | #ifdef MP_DEBUG |
---|
968 | fprintf(stderr, |
---|
969 | "socket_accept_non_blocking: entering - socket = %d\n", *sock); |
---|
970 | fflush(stderr); |
---|
971 | #endif |
---|
972 | |
---|
973 | timeout.tv_sec = MP_ACCEPT_WAIT_SEC; |
---|
974 | timeout.tv_usec = MP_ACCEPT_WAIT_USEC; |
---|
975 | |
---|
976 | for (attempts = 0; attempts < 2; attempts++) { |
---|
977 | FD_ZERO(&read_template); |
---|
978 | FD_SET(*sock, &read_template); |
---|
979 | |
---|
980 | if (SELECT(FD_SETSIZE, &read_template, NULL, NULL, &timeout) |
---|
981 | != SOCKET_ERROR) { |
---|
982 | |
---|
983 | if ((nsock = accept(*sock, &addr, &addrlen)) != INVALID_SOCKET) |
---|
984 | break; |
---|
985 | |
---|
986 | sprintf(log_msg, |
---|
987 | "socket_accept_non_blocking: failed (socket error %d)", |
---|
988 | LASTERROR); |
---|
989 | MP_LogEvent(link, MP_ERROR_EVENT, log_msg); |
---|
990 | return MP_Failure; |
---|
991 | } |
---|
992 | } |
---|
993 | |
---|
994 | *sock = nsock; |
---|
995 | |
---|
996 | #ifdef MP_DEBUG |
---|
997 | fprintf(stderr, |
---|
998 | "socket_accept_non_blocking: returning - new socket = %d\n", |
---|
999 | *sock); |
---|
1000 | fflush(stderr); |
---|
1001 | #endif |
---|
1002 | |
---|
1003 | return MP_Success; |
---|
1004 | } |
---|
1005 | |
---|
1006 | |
---|
1007 | |
---|
1008 | /*********************************************************************** |
---|
1009 | * FUNCTION: socket_accept_blocking |
---|
1010 | * INPUT: link - link with which sock will be associated, need this |
---|
1011 | * really only for the error handling. |
---|
1012 | * sock - the socket to do the accept on |
---|
1013 | * OUTPUT: int - Success: the socket to be used for io |
---|
1014 | * Failure: MP_Failure |
---|
1015 | * PURPOSE: Perform a blocking accept. We won't return until we get an |
---|
1016 | * connect request or are interrupted. |
---|
1017 | ***********************************************************************/ |
---|
1018 | #ifdef __STDC__ |
---|
1019 | MP_Status_t socket_accept_blocking(MP_Link_pt link, SOCKET *sock) |
---|
1020 | #else |
---|
1021 | MP_Status_t socket_accept_blocking (link, sock) |
---|
1022 | MP_Link_pt link; |
---|
1023 | SOCKET *sock; |
---|
1024 | #endif |
---|
1025 | { |
---|
1026 | SOCKADDR addr; |
---|
1027 | SOCKET nsock = 0; |
---|
1028 | int attempts, addrlen = sizeof(addr); |
---|
1029 | fd_set read_template; |
---|
1030 | |
---|
1031 | #ifdef MP_DEBUG |
---|
1032 | fprintf(stderr, "socket_accept_blocking: entering - sock = %d\n", *sock); |
---|
1033 | fflush(stderr); |
---|
1034 | #endif |
---|
1035 | |
---|
1036 | for (attempts = 0; attempts < 2; attempts++) { |
---|
1037 | FD_ZERO(&read_template); |
---|
1038 | FD_SET(*sock, &read_template); |
---|
1039 | |
---|
1040 | if (SELECT(FD_SETSIZE, &read_template, NULL, NULL, NULL) |
---|
1041 | != SOCKET_ERROR) { |
---|
1042 | if ((nsock = accept(*sock, &addr, &addrlen)) != INVALID_SOCKET) |
---|
1043 | break; |
---|
1044 | |
---|
1045 | sprintf(log_msg, |
---|
1046 | "socket_accept_blocking: failed (socket error %d)", |
---|
1047 | LASTERROR); |
---|
1048 | MP_LogEvent(link, MP_ERROR_EVENT, log_msg); |
---|
1049 | return MP_Failure; |
---|
1050 | } |
---|
1051 | } |
---|
1052 | |
---|
1053 | *sock = nsock; |
---|
1054 | |
---|
1055 | #ifdef MP_DEBUG |
---|
1056 | fprintf(stderr, "socket_accept_blocking: returning - new socket = %d\n", *sock); |
---|
1057 | fflush(stderr); |
---|
1058 | #endif |
---|
1059 | |
---|
1060 | return MP_Success; |
---|
1061 | } |
---|
1062 | |
---|
1063 | |
---|
1064 | |
---|
1065 | |
---|
1066 | |
---|
1067 | /**** TCP "public" routines ******/ |
---|
1068 | |
---|
1069 | #ifdef __STDC__ |
---|
1070 | MP_Boolean_t tcp_get_status(MP_Link_pt link, MP_LinkStatus_t status_to_check) |
---|
1071 | #else |
---|
1072 | MP_Boolean_t tcp_get_status(link, status_to_check) |
---|
1073 | MP_Link_pt link; |
---|
1074 | MP_LinkStatus_t status_to_check; |
---|
1075 | #endif |
---|
1076 | { |
---|
1077 | SOCKET sock = ((MP_TCP_t *)link->transp.private1)->sock; |
---|
1078 | fd_set mask, fdmask; |
---|
1079 | TIMEVAL wt; |
---|
1080 | |
---|
1081 | #ifdef MP_DEBUG |
---|
1082 | printf("tcp_get_status: entering for link %d\n", link->link_id); |
---|
1083 | #endif |
---|
1084 | if (status_to_check == MP_LinkIsParent) |
---|
1085 | { |
---|
1086 | if (((MP_TCP_t *)link->transp.private1)->status == MP_LinkIsParent) |
---|
1087 | return MP_TRUE; |
---|
1088 | else |
---|
1089 | return MP_FALSE; |
---|
1090 | } |
---|
1091 | else if (status_to_check == MP_LinkIsChild) |
---|
1092 | { |
---|
1093 | if (((MP_TCP_t *)link->transp.private1)->status == MP_LinkIsChild) |
---|
1094 | return MP_TRUE; |
---|
1095 | else |
---|
1096 | return MP_FALSE; |
---|
1097 | } |
---|
1098 | |
---|
1099 | |
---|
1100 | FD_ZERO(&mask); |
---|
1101 | FD_SET(sock, &mask); |
---|
1102 | |
---|
1103 | fdmask = mask; |
---|
1104 | |
---|
1105 | /* Don't block. Return socket status immediately. */ |
---|
1106 | wt.tv_sec = 0; |
---|
1107 | wt.tv_usec = 0; |
---|
1108 | |
---|
1109 | switch (status_to_check) { |
---|
1110 | case MP_LinkReadyReading: |
---|
1111 | switch (SELECT(FD_SETSIZE, &fdmask, NULL, NULL, &wt)) { |
---|
1112 | case 0: |
---|
1113 | return MP_FALSE; |
---|
1114 | case SOCKET_ERROR: |
---|
1115 | return MP_FALSE; |
---|
1116 | } |
---|
1117 | if (FD_ISSET(sock, &fdmask)) |
---|
1118 | return MP_TRUE; |
---|
1119 | |
---|
1120 | return MP_FALSE; |
---|
1121 | |
---|
1122 | case MP_LinkReadyWriting: |
---|
1123 | switch (SELECT(FD_SETSIZE, NULL, &fdmask, NULL, &wt)) { |
---|
1124 | case 0: |
---|
1125 | return MP_FALSE; |
---|
1126 | case SOCKET_ERROR: |
---|
1127 | return MP_FALSE; |
---|
1128 | } |
---|
1129 | if (FD_ISSET(sock, &fdmask)) |
---|
1130 | return MP_TRUE; |
---|
1131 | |
---|
1132 | return MP_FALSE; |
---|
1133 | |
---|
1134 | default: |
---|
1135 | sprintf(log_msg, |
---|
1136 | "tcp_get_status: illegal option %d", status_to_check); |
---|
1137 | MP_LogEvent(link, MP_ERROR_EVENT, log_msg); |
---|
1138 | } |
---|
1139 | |
---|
1140 | #ifdef MP_DEBUG |
---|
1141 | printf("tcp_get_status: exiting\n"); |
---|
1142 | #endif |
---|
1143 | |
---|
1144 | return MP_FALSE; |
---|
1145 | } |
---|
1146 | |
---|
1147 | |
---|
1148 | |
---|
1149 | #ifdef __STDC__ |
---|
1150 | long tcp_read(MP_Link_pt link, char * buf, long len) |
---|
1151 | #else |
---|
1152 | long tcp_read(link, buf, len) |
---|
1153 | MP_Link_pt link; |
---|
1154 | char * buf; |
---|
1155 | long len; |
---|
1156 | #endif |
---|
1157 | { |
---|
1158 | SOCKET sock = ((MP_TCP_t *)link->transp.private1)->sock; |
---|
1159 | fd_set mask, readfs; |
---|
1160 | long total = 0, n; |
---|
1161 | |
---|
1162 | #ifdef MP_DEBUG |
---|
1163 | fprintf(stderr, "tcp_read: entering - len = %ld\n", len); |
---|
1164 | fflush(stderr); |
---|
1165 | #endif |
---|
1166 | |
---|
1167 | while (len > 0) { |
---|
1168 | FD_ZERO(&mask); |
---|
1169 | FD_SET(sock, &mask); |
---|
1170 | |
---|
1171 | while (MP_TRUE) { |
---|
1172 | readfs = mask; |
---|
1173 | |
---|
1174 | /* Do blocking read. */ |
---|
1175 | switch (SELECT(FD_SETSIZE, &readfs, NULL, NULL, NULL)) { |
---|
1176 | case 0: |
---|
1177 | MP_LogEvent(link, MP_ERROR_EVENT, "tcp_read: timed out"); |
---|
1178 | return -1; |
---|
1179 | |
---|
1180 | case SOCKET_ERROR: |
---|
1181 | if (LASTERROR == ERRORCODE(EINTR)) |
---|
1182 | continue; |
---|
1183 | return -1; |
---|
1184 | } |
---|
1185 | |
---|
1186 | if (FD_ISSET(sock, &readfs)) |
---|
1187 | break; |
---|
1188 | } |
---|
1189 | |
---|
1190 | if ((n = READ_SOCKET(sock, buf, len)) == SOCKET_ERROR) { |
---|
1191 | sprintf(log_msg, "tcp_read: can't do read (socket error %d)", |
---|
1192 | LASTERROR); |
---|
1193 | MP_LogEvent(link, MP_ERROR_EVENT, log_msg); |
---|
1194 | return MP_SetError(link, MP_CantReadLink); |
---|
1195 | } |
---|
1196 | |
---|
1197 | total += n; |
---|
1198 | len -= n; |
---|
1199 | buf += n; |
---|
1200 | } |
---|
1201 | |
---|
1202 | #ifndef NO_LOGGING |
---|
1203 | if (link->logmask & MP_LOG_READ_EVENTS) { |
---|
1204 | sprintf(log_msg, "tcp_read: read %ld bytes", total); |
---|
1205 | MP_LogEvent(link, MP_READ_EVENT, log_msg); |
---|
1206 | } |
---|
1207 | #endif /* NO_LOGGING */ |
---|
1208 | |
---|
1209 | #ifdef MP_DEBUG |
---|
1210 | fprintf(stderr, "tcp_read: exiting - read %ld bytes \n", total); |
---|
1211 | fflush(stderr); |
---|
1212 | #endif /* MP_DEBUG */ |
---|
1213 | |
---|
1214 | return total; |
---|
1215 | } |
---|
1216 | |
---|
1217 | |
---|
1218 | MP_Status_t |
---|
1219 | #ifdef __STDC__ |
---|
1220 | tcp_flush(MP_Link_pt link) |
---|
1221 | #else |
---|
1222 | tcp_flush(link) |
---|
1223 | MP_Link_pt link; |
---|
1224 | #endif |
---|
1225 | { |
---|
1226 | |
---|
1227 | #ifdef MP_DEBUG |
---|
1228 | fprintf(stderr, "tcp_flush: entering\n"); |
---|
1229 | fflush(stderr); |
---|
1230 | #endif |
---|
1231 | #ifdef MP_DEBUG |
---|
1232 | fprintf(stderr, "tcp_flush: exiting \n"); |
---|
1233 | fflush(stderr); |
---|
1234 | #endif |
---|
1235 | return MP_ClearError(link); |
---|
1236 | } |
---|
1237 | |
---|
1238 | |
---|
1239 | #ifdef __STDC__ |
---|
1240 | long tcp_write(MP_Link_pt link, |
---|
1241 | char * buf, |
---|
1242 | long len) |
---|
1243 | #else |
---|
1244 | long tcp_write(link, buf, len) |
---|
1245 | MP_Link_pt link; |
---|
1246 | char * buf; |
---|
1247 | long len; |
---|
1248 | #endif |
---|
1249 | { |
---|
1250 | long i, cnt; |
---|
1251 | SOCKET sock = ((MP_TCP_t *)link->transp.private1)->sock; |
---|
1252 | fd_set mask, writefs; |
---|
1253 | |
---|
1254 | #ifdef MP_DEBUG |
---|
1255 | fprintf(stderr, "tcp_write: entering - len = %ld\n", len); |
---|
1256 | fflush(stderr); |
---|
1257 | #endif |
---|
1258 | |
---|
1259 | FD_ZERO(&mask); |
---|
1260 | FD_SET(sock, &mask); |
---|
1261 | |
---|
1262 | while (MP_TRUE) { |
---|
1263 | writefs = mask; |
---|
1264 | switch (SELECT(FD_SETSIZE, NULL, &writefs, NULL, NULL)) { |
---|
1265 | case 0: |
---|
1266 | MP_LogEvent(link, MP_ERROR_EVENT, "tcp_write: timed out"); |
---|
1267 | return -1; |
---|
1268 | |
---|
1269 | case SOCKET_ERROR: |
---|
1270 | if (LASTERROR == ERRORCODE(EINTR)) |
---|
1271 | continue; |
---|
1272 | MP_LogEvent(link, MP_ERROR_EVENT, |
---|
1273 | "tcp_write: errno isn't EINTR - this is bad"); |
---|
1274 | return -1; |
---|
1275 | } |
---|
1276 | |
---|
1277 | if (FD_ISSET(sock, &writefs)) |
---|
1278 | break; |
---|
1279 | } |
---|
1280 | |
---|
1281 | |
---|
1282 | for (cnt = len; cnt > 0; cnt -= i, buf += i) { |
---|
1283 | if ((i = WRITE_SOCKET(sock, buf, cnt)) == SOCKET_ERROR) { |
---|
1284 | sprintf(log_msg, "tcp_write: can't do write (socket error %d)", |
---|
1285 | LASTERROR); |
---|
1286 | MP_LogEvent(link, MP_ERROR_EVENT, log_msg); |
---|
1287 | return MP_SetError(link, MP_CantWriteLink); |
---|
1288 | } |
---|
1289 | |
---|
1290 | #ifndef NO_LOGGING |
---|
1291 | if (link->logmask & MP_LOG_WRITE_EVENTS) { |
---|
1292 | sprintf(log_msg, "tcp_write: wrote %ld bytes", i); |
---|
1293 | MP_LogEvent(link, MP_WRITE_EVENT, log_msg); |
---|
1294 | } |
---|
1295 | #endif /* NO_LOGGING */ |
---|
1296 | } |
---|
1297 | |
---|
1298 | #ifdef MP_DEBUG |
---|
1299 | fprintf(stderr, "tcp_write: exiting - wrote %ld bytes \n", i); |
---|
1300 | fflush(stderr); |
---|
1301 | #endif |
---|
1302 | |
---|
1303 | return len; |
---|
1304 | } |
---|
1305 | |
---|
1306 | |
---|
1307 | |
---|
1308 | /*********************************************************************** |
---|
1309 | * FUNCTION: tcp_init_transport |
---|
1310 | * INPUT: link - pointer to the link structure for this connection |
---|
1311 | * OUTPUT: Success: MP_Success and link structure initialized for the |
---|
1312 | * tcp connection. |
---|
1313 | * Failure: MP_Failure |
---|
1314 | * OPERATION: If there are no problems, allocate a tcp structure and |
---|
1315 | * attach it to the private pointer inside link. |
---|
1316 | ***********************************************************************/ |
---|
1317 | #ifdef __STDC__ |
---|
1318 | MP_Status_t tcp_init_transport(MP_Link_pt link) |
---|
1319 | #else |
---|
1320 | MP_Status_t tcp_init_transport(link) |
---|
1321 | MP_Link_pt link; |
---|
1322 | #endif |
---|
1323 | { |
---|
1324 | MP_TCP_t *tcp_rec; |
---|
1325 | |
---|
1326 | #ifdef MP_DEBUG |
---|
1327 | fprintf(stderr, "tcp_init_transport: entering\n"); fflush(stderr); |
---|
1328 | #endif |
---|
1329 | |
---|
1330 | TEST_LINK_NULL(link); |
---|
1331 | link->transp.transp_dev = MP_TcpTransportDev; |
---|
1332 | link->transp.transp_ops = &tcp_ops; |
---|
1333 | |
---|
1334 | tcp_rec = (MP_TCP_t*)IMP_MemAllocFnc(sizeof(MP_TCP_t)); |
---|
1335 | TEST_MEM_ALLOC_ERROR(link, tcp_rec); |
---|
1336 | |
---|
1337 | /* Initialize TCP record. */ |
---|
1338 | tcp_rec->bindsock = INVALID_SOCKET; |
---|
1339 | tcp_rec->sock = INVALID_SOCKET; |
---|
1340 | tcp_rec->peerport = 0; |
---|
1341 | tcp_rec->myhost = NULL; |
---|
1342 | tcp_rec->peerhost = NULL; |
---|
1343 | tcp_rec->status = MP_UnknownStatus; |
---|
1344 | tcp_rec->rsh = NULL; |
---|
1345 | |
---|
1346 | link->transp.private1 = (char *)tcp_rec; |
---|
1347 | |
---|
1348 | #ifdef MP_DEBUG |
---|
1349 | fprintf(stderr, "tcp_init_transport: exiting\n"); |
---|
1350 | fflush(stderr); |
---|
1351 | #endif |
---|
1352 | |
---|
1353 | RETURN_OK(link); |
---|
1354 | } |
---|
1355 | |
---|
1356 | /*********************************************************************** |
---|
1357 | * FUNCTION: tcp_close_connection |
---|
1358 | * INPUT: link - pointer to the link structure for this connection |
---|
1359 | * OUTPUT: Success: MP_Success |
---|
1360 | * Release the tcp structure pointed to by private1. |
---|
1361 | * Failure: MP_Failure |
---|
1362 | * OPERATION: |
---|
1363 | ***********************************************************************/ |
---|
1364 | #ifdef __STDC__ |
---|
1365 | MP_Status_t tcp_close_connection(MP_Link_pt link) |
---|
1366 | #else |
---|
1367 | MP_Status_t tcp_close_connection(link) |
---|
1368 | MP_Link_pt link; |
---|
1369 | #endif |
---|
1370 | { |
---|
1371 | MP_TCP_t *tcp_rec; |
---|
1372 | |
---|
1373 | #ifdef MP_DEBUG |
---|
1374 | fprintf(stderr, "tcp_close_connection: entering\n"); |
---|
1375 | fflush(stderr); |
---|
1376 | #endif /* MP_DEBUG */ |
---|
1377 | |
---|
1378 | TEST_LINK_NULL(link); |
---|
1379 | if (link->transp.private1 == NULL) |
---|
1380 | return MP_SetError(link, MP_NullTransport); |
---|
1381 | tcp_rec = (MP_TCP_t*)link->transp.private1; |
---|
1382 | |
---|
1383 | CLOSE_SOCKET(tcp_rec->sock); |
---|
1384 | if (tcp_rec->bindsock != INVALID_SOCKET) |
---|
1385 | CLOSE_SOCKET(tcp_rec->bindsock); |
---|
1386 | |
---|
1387 | if (tcp_rec->myhost != NULL) |
---|
1388 | IMP_RawMemFreeFnc(tcp_rec->myhost); |
---|
1389 | if (tcp_rec->peerhost != NULL) |
---|
1390 | IMP_RawMemFreeFnc(tcp_rec->peerhost); |
---|
1391 | if (tcp_rec->rsh != NULL) |
---|
1392 | IMP_RawMemFreeFnc(tcp_rec->rsh); |
---|
1393 | IMP_MemFreeFnc(tcp_rec, sizeof(MP_TCP_t)); |
---|
1394 | link->transp.private1 = NULL; |
---|
1395 | |
---|
1396 | #ifdef MP_DEBUG |
---|
1397 | fprintf(stderr, "tcp_close_connection: exiting\n"); |
---|
1398 | fflush(stderr); |
---|
1399 | #endif /* MP_DEBUG */ |
---|
1400 | |
---|
1401 | RETURN_OK(link); |
---|
1402 | } |
---|
1403 | |
---|
1404 | #ifdef __STDC__ |
---|
1405 | MP_Status_t tcp_kill_connection(MP_Link_pt link) |
---|
1406 | #else |
---|
1407 | MP_Status_t tcp_kill_connection(link) |
---|
1408 | MP_Link_pt link; |
---|
1409 | #endif |
---|
1410 | { |
---|
1411 | MP_TCP_t *tcp_rec; |
---|
1412 | int fork_pid = -1; |
---|
1413 | |
---|
1414 | #ifdef MP_DEBUG |
---|
1415 | fprintf(stderr, "tcp_kill_connection: entering\n"); |
---|
1416 | fflush(stderr); |
---|
1417 | #endif /* MP_DEBUG */ |
---|
1418 | |
---|
1419 | TEST_LINK_NULL(link); |
---|
1420 | if (link->transp.private1 == NULL) |
---|
1421 | return MP_SetError(link, MP_NullTransport); |
---|
1422 | tcp_rec = (MP_TCP_t*)link->transp.private1; |
---|
1423 | |
---|
1424 | if (tcp_rec->mode == MP_LAUNCH_MODE) |
---|
1425 | { |
---|
1426 | char *rsh_argv[5]; |
---|
1427 | char rsh_kill[20]; |
---|
1428 | rsh_argv[0] = tcp_rec->rsh; |
---|
1429 | rsh_argv[1] = tcp_rec->peerhost; |
---|
1430 | rsh_argv[2] = "-n"; |
---|
1431 | sprintf(rsh_kill, "kill -9 %d", tcp_rec->peerpid); |
---|
1432 | rsh_argv[3] = rsh_kill; |
---|
1433 | rsh_argv[4] = NULL; |
---|
1434 | |
---|
1435 | if ((fork_pid = vfork()) == -1) |
---|
1436 | { |
---|
1437 | MP_LogEvent(link, MP_ERROR_EVENT, |
---|
1438 | "MP_OpenLink: can't fork to kill application"); |
---|
1439 | return MP_SetError(link, MP_Failure); |
---|
1440 | } |
---|
1441 | |
---|
1442 | if (! fork_pid) |
---|
1443 | { |
---|
1444 | execvp(rsh_argv[0], rsh_argv); |
---|
1445 | fputs("tcp_kill_connection: execvp failed - bailing out\n", stderr); |
---|
1446 | fflush(stderr); |
---|
1447 | _exit(1); |
---|
1448 | } |
---|
1449 | } |
---|
1450 | else if (tcp_rec->mode == MP_FORK_MODE) |
---|
1451 | { |
---|
1452 | kill(tcp_rec->peerpid, SIGKILL); |
---|
1453 | } |
---|
1454 | |
---|
1455 | return tcp_close_connection(link); |
---|
1456 | } |
---|
1457 | |
---|
1458 | /*********************************************************************** |
---|
1459 | * FUNCTION: tcp_open_connection |
---|
1460 | * INPUT: link - pointer to link structure for this connection |
---|
1461 | * argc - number of arguments in argv |
---|
1462 | * argv - arguments as strings |
---|
1463 | * OUTPUT: Success: MP_Success |
---|
1464 | * link established as a tcp connection |
---|
1465 | * Failure: MP_Failure |
---|
1466 | * OPERATION: Determine the tcp mode we are using and attempt to |
---|
1467 | * establish a connection accordingly. We could fail |
---|
1468 | * for any of a number of reasons. Bad hostname, bad |
---|
1469 | * port number, missing arguments.... |
---|
1470 | ***********************************************************************/ |
---|
1471 | #ifdef __STDC__ |
---|
1472 | MP_Status_t tcp_open_connection(MP_Link_pt link, |
---|
1473 | int argc, |
---|
1474 | char **argv) |
---|
1475 | #else |
---|
1476 | MP_Status_t tcp_open_connection(link, argc, argv) |
---|
1477 | MP_Link_pt link; |
---|
1478 | int argc; |
---|
1479 | char **argv; |
---|
1480 | #endif |
---|
1481 | { |
---|
1482 | MP_Status_t status; |
---|
1483 | struct protoent *protostruct = NULL; |
---|
1484 | int sockopt; |
---|
1485 | |
---|
1486 | #ifdef MP_DEBUG |
---|
1487 | fprintf(stderr, "tcp_open_connection: entering\n"); |
---|
1488 | fflush(stderr); |
---|
1489 | #endif |
---|
1490 | |
---|
1491 | TEST_LINK_NULL(link); |
---|
1492 | if (tcp_init_transport(link) != MP_Success) |
---|
1493 | return MP_Failure; |
---|
1494 | |
---|
1495 | ((MP_TCP_t *)link->transp.private1)->mode = get_tcp_mode(argc, argv); |
---|
1496 | switch (((MP_TCP_t *)link->transp.private1)->mode) |
---|
1497 | { |
---|
1498 | case MP_LISTEN_MODE: |
---|
1499 | status = open_tcp_listen_mode(link, argc, argv); |
---|
1500 | if (status != MP_Success) |
---|
1501 | break; |
---|
1502 | status = socket_accept_blocking(link, |
---|
1503 | &((MP_TCP_t *)link->transp.private1)->sock); |
---|
1504 | break; |
---|
1505 | |
---|
1506 | case MP_CONNECT_MODE: |
---|
1507 | status = open_tcp_connect_mode(link, argc, argv); |
---|
1508 | break; |
---|
1509 | |
---|
1510 | case MP_LAUNCH_MODE: |
---|
1511 | status = open_tcp_launch_mode(link, argc, argv); |
---|
1512 | break; |
---|
1513 | |
---|
1514 | case MP_FORK_MODE: |
---|
1515 | status = open_tcp_fork_mode(link, argc, argv); |
---|
1516 | break; |
---|
1517 | |
---|
1518 | default: |
---|
1519 | MP_LogEvent(link, MP_ERROR_EVENT, |
---|
1520 | "Can't open connection, unknown -MPmode argument"); |
---|
1521 | return MP_SetError(link, MP_Failure); |
---|
1522 | } |
---|
1523 | |
---|
1524 | if (status != MP_Success) |
---|
1525 | return MP_Failure; |
---|
1526 | |
---|
1527 | /* get the protocol number for TCP from /etc/protocols */ |
---|
1528 | if ((protostruct = getprotobyname("tcp")) == NULL) { |
---|
1529 | MP_LogEvent(link, MP_ERROR_EVENT, |
---|
1530 | "Can't open connection: can't get TCP protocol info!!"); |
---|
1531 | return MP_SetError(link, MP_Failure); |
---|
1532 | } |
---|
1533 | |
---|
1534 | /* set socket to not coalesce small amounts of data in a single packet */ |
---|
1535 | if (setsockopt(((MP_TCP_t *)link->transp.private1)->sock, |
---|
1536 | protostruct->p_proto, TCP_NODELAY, &sockopt, sizeof(int)) == -1) { |
---|
1537 | MP_LogEvent(link, MP_ERROR_EVENT, |
---|
1538 | "Can't open connection: can't set NODELAY option on socket"); |
---|
1539 | return MP_SetError(link, MP_Failure); |
---|
1540 | } |
---|
1541 | |
---|
1542 | ERR_CHK(tcp_negotiate_word_order(link)); |
---|
1543 | ERR_CHK(tcp_negotiate_fp_format(link)); |
---|
1544 | ERR_CHK(tcp_negotiate_bigint_format(link)); |
---|
1545 | ERR_CHK(tcp_exchange_pids(link)); |
---|
1546 | |
---|
1547 | #ifdef MP_DEBUG |
---|
1548 | fprintf(stderr, "tcp_open_connection: exiting\n"); |
---|
1549 | fflush(stderr); |
---|
1550 | #endif |
---|
1551 | |
---|
1552 | RETURN_OK(link); |
---|
1553 | } |
---|
1554 | |
---|
1555 | |
---|
1556 | #ifdef __STDC__ |
---|
1557 | static MP_Status_t tcp_exchange_pids(MP_Link_pt link) |
---|
1558 | #else |
---|
1559 | static MP_Status_t tcp_exchange_pids(link) |
---|
1560 | MP_Link_pt link; |
---|
1561 | #endif |
---|
1562 | { |
---|
1563 | MP_Uint32_t peerpid; |
---|
1564 | MP_NumAnnot_t na; |
---|
1565 | |
---|
1566 | /* Hmm... should communicate pid_t -- could be 64 bit !! */ |
---|
1567 | ERR_CHK(MP_PutUint32Packet(link, (MP_Uint32_t) getpid(), 0)); |
---|
1568 | MP_EndMsgReset(link); |
---|
1569 | |
---|
1570 | ERR_CHK(MP_SkipMsg(link)); |
---|
1571 | ERR_CHK(MP_GetUint32Packet(link, &peerpid, &na)); |
---|
1572 | ((MP_TCP_t *)link->transp.private1)->peerpid = peerpid; |
---|
1573 | |
---|
1574 | return MP_Success; |
---|
1575 | } |
---|
1576 | |
---|
1577 | /* |
---|
1578 | * Currently this is a canned routine. There is little parsing. It |
---|
1579 | * assumes that the first thing the two partners will do is to negotiate |
---|
1580 | * the word order. If that is a correct assumption, this should work |
---|
1581 | * like a champ, otherwise we are in trouble. |
---|
1582 | */ |
---|
1583 | #ifdef __STDC__ |
---|
1584 | static MP_Status_t tcp_negotiate_word_order(MP_Link_pt link) |
---|
1585 | #else |
---|
1586 | static MP_Status_t tcp_negotiate_word_order(link) |
---|
1587 | MP_Link_pt link; |
---|
1588 | #endif |
---|
1589 | { |
---|
1590 | MP_DictTag_t dtag; |
---|
1591 | MP_NumAnnot_t na; |
---|
1592 | MP_NumChild_t nc; |
---|
1593 | unsigned long req_word_order; |
---|
1594 | MP_Common_t mp_op; |
---|
1595 | |
---|
1596 | /* |
---|
1597 | * Step 1: We send our word order preference to our partner |
---|
1598 | */ |
---|
1599 | ERR_CHK(MP_PutCommonOperatorPacket(link, MP_MpDict, |
---|
1600 | MP_CopMpByteOrderRequest, 0, 1)); |
---|
1601 | ERR_CHK(IMP_PutUint32(link, (unsigned long)link->env->native_word_order)); |
---|
1602 | MP_EndMsgReset(link); |
---|
1603 | |
---|
1604 | /* |
---|
1605 | * Step 2: Get a reply. It should be MP_CopMpByteOrderRequest. |
---|
1606 | * Probably should peek at the data stream here to be sure we are |
---|
1607 | * getting the right thing. |
---|
1608 | */ |
---|
1609 | ERR_CHK(MP_SkipMsg(link)); |
---|
1610 | ERR_CHK(MP_GetCommonOperatorPacket(link, &dtag, &mp_op, &na, &nc)); |
---|
1611 | ERR_CHK(IMP_GetUint32(link, &req_word_order)); |
---|
1612 | |
---|
1613 | if (mp_op != MP_CopMpByteOrderRequest || dtag != MP_MpDict) { |
---|
1614 | MP_LogEvent(link, MP_ERROR_EVENT, |
---|
1615 | "Problem exchanging initialization information: byte order"); |
---|
1616 | return MP_Failure; |
---|
1617 | } |
---|
1618 | |
---|
1619 | |
---|
1620 | /* |
---|
1621 | * We only have to do something if the word order has changed. |
---|
1622 | * This will only happen if both parties are Little Endian |
---|
1623 | */ |
---|
1624 | if (req_word_order == (unsigned long)link->env->native_word_order |
---|
1625 | && link->env->native_word_order != link->link_word_order) { |
---|
1626 | link->link_word_order = link->env->native_word_order; |
---|
1627 | MP_LogEvent(link, MP_INIT_EVENT, |
---|
1628 | "Link word order changed to Little Endian"); |
---|
1629 | } |
---|
1630 | |
---|
1631 | return MP_Success; |
---|
1632 | } |
---|
1633 | |
---|
1634 | |
---|
1635 | |
---|
1636 | #ifdef __STDC__ |
---|
1637 | static MP_Status_t tcp_negotiate_fp_format(MP_Link_pt link) |
---|
1638 | #else |
---|
1639 | static MP_Status_t tcp_negotiate_fp_format(link) |
---|
1640 | MP_Link_pt link; |
---|
1641 | #endif |
---|
1642 | { |
---|
1643 | MP_DictTag_t dtag; |
---|
1644 | MP_NumAnnot_t na; |
---|
1645 | MP_NumChild_t nc; |
---|
1646 | unsigned long req_fp_format; |
---|
1647 | MP_Common_t mp_op; |
---|
1648 | |
---|
1649 | |
---|
1650 | #ifdef MP_DEBUG |
---|
1651 | printf("tcp_negotiate_fp_format: entering\n"); |
---|
1652 | #endif |
---|
1653 | |
---|
1654 | /* |
---|
1655 | * Step 1: We send our fp format preference to our partner |
---|
1656 | */ |
---|
1657 | ERR_CHK(MP_PutCommonOperatorPacket(link, MP_MpDict, |
---|
1658 | MP_CopMpFpFormatRequest, 0, 1)); |
---|
1659 | ERR_CHK(IMP_PutUint32(link, (unsigned long)link->env->native_fp_format)); |
---|
1660 | MP_EndMsgReset(link); |
---|
1661 | |
---|
1662 | /* |
---|
1663 | * Step 2: Get a reply. It should be "MP_FpFormatRequest" |
---|
1664 | * probably should peek at the data stream here to be sure we are |
---|
1665 | * getting the right thing |
---|
1666 | */ |
---|
1667 | ERR_CHK(MP_SkipMsg(link)); |
---|
1668 | ERR_CHK(MP_GetCommonOperatorPacket(link, &dtag, &mp_op, &na, &nc)); |
---|
1669 | ERR_CHK(IMP_GetUint32(link, &req_fp_format)); |
---|
1670 | |
---|
1671 | if (mp_op != MP_CopMpFpFormatRequest || dtag != MP_MpDict) { |
---|
1672 | MP_LogEvent(link, MP_ERROR_EVENT, |
---|
1673 | "Problem exchanging initialization information: fp format"); |
---|
1674 | return MP_Failure; |
---|
1675 | } |
---|
1676 | |
---|
1677 | /* |
---|
1678 | * We only have to do something if the fp format has changed. |
---|
1679 | * This will only happen if both parties are something other than IEEE. |
---|
1680 | */ |
---|
1681 | if (req_fp_format == (unsigned long)link->env->native_fp_format |
---|
1682 | && link->env->native_fp_format != link->link_fp_format) { |
---|
1683 | link->link_fp_format = link->env->native_fp_format; |
---|
1684 | MP_LogEvent(link, MP_INIT_EVENT, |
---|
1685 | "Link floating point format changed to VAX"); |
---|
1686 | } |
---|
1687 | |
---|
1688 | #ifdef MP_DEBUG |
---|
1689 | printf("tcp_negotiate_fp_format: exiting\n"); |
---|
1690 | #endif |
---|
1691 | |
---|
1692 | return MP_Success; |
---|
1693 | } |
---|
1694 | |
---|
1695 | |
---|
1696 | |
---|
1697 | #ifdef __STDC__ |
---|
1698 | static MP_Status_t tcp_negotiate_bigint_format(MP_Link_pt link) |
---|
1699 | #else |
---|
1700 | static MP_Status_t tcp_negotiate_bigint_format(link) |
---|
1701 | MP_Link_pt link; |
---|
1702 | #endif |
---|
1703 | { |
---|
1704 | MP_DictTag_t dtag; |
---|
1705 | MP_NumAnnot_t na; |
---|
1706 | MP_NumChild_t nc; |
---|
1707 | unsigned long req_bigint_format; |
---|
1708 | MP_Common_t mp_op; |
---|
1709 | |
---|
1710 | #ifdef MP_DEBUG |
---|
1711 | printf("tcp_negotiate_bigint_format: entering\n"); |
---|
1712 | #endif |
---|
1713 | |
---|
1714 | /* |
---|
1715 | * Step 1: We send our bigint format preference to our partner |
---|
1716 | */ |
---|
1717 | ERR_CHK(MP_PutCommonOperatorPacket(link, MP_MpDict, |
---|
1718 | MP_CopMpBigIntFormatRequest, 0, 1)); |
---|
1719 | ERR_CHK(IMP_PutUint32(link, (unsigned long)link->link_bigint_format)); |
---|
1720 | MP_EndMsgReset(link); |
---|
1721 | |
---|
1722 | /* |
---|
1723 | * Step 2: Get a reply. It should be "MP_BigIntFormatRequest" |
---|
1724 | * probably should peek at the data stream here to be sure we are |
---|
1725 | * getting the right thing |
---|
1726 | */ |
---|
1727 | ERR_CHK(MP_SkipMsg(link)); |
---|
1728 | ERR_CHK(MP_GetCommonOperatorPacket(link, &dtag, &mp_op, &na, &nc)); |
---|
1729 | ERR_CHK(IMP_GetUint32(link, &req_bigint_format)); |
---|
1730 | |
---|
1731 | if (mp_op != MP_CopMpBigIntFormatRequest || dtag != MP_MpDict) { |
---|
1732 | MP_LogEvent(link, MP_ERROR_EVENT, |
---|
1733 | "Problem exchanging initialization information: big int format"); |
---|
1734 | return MP_Failure; |
---|
1735 | } |
---|
1736 | |
---|
1737 | /* |
---|
1738 | * We only have to do something if both ends are not already the same |
---|
1739 | */ |
---|
1740 | if (req_bigint_format != (unsigned long)link->link_bigint_format) { |
---|
1741 | link->link_bigint_format = MP_GMP; |
---|
1742 | MP_LogEvent(link, MP_INIT_EVENT, |
---|
1743 | "Link multiple precision integer format set to GMP"); |
---|
1744 | } |
---|
1745 | |
---|
1746 | #ifdef MP_DEBUG |
---|
1747 | printf("tcp_negotiate_bigint_format: exiting\n"); |
---|
1748 | #endif |
---|
1749 | |
---|
1750 | return MP_Success; |
---|
1751 | } |
---|
1752 | |
---|
1753 | |
---|
1754 | |
---|
1755 | #ifdef __STDC__ |
---|
1756 | MP_Status_t tcp_get_port(SOCKET *sock, short *port) |
---|
1757 | #else |
---|
1758 | MP_Status_t tcp_get_port(sock, port) |
---|
1759 | SOCKET *s; |
---|
1760 | short *port; |
---|
1761 | #endif |
---|
1762 | { |
---|
1763 | SOCKADDR_IN isin; |
---|
1764 | int attempts = 0; |
---|
1765 | |
---|
1766 | if (*port < IPPORT_RESERVED) |
---|
1767 | *port = IPPORT_RESERVED; |
---|
1768 | |
---|
1769 | if ((*sock = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) |
---|
1770 | return MP_Failure; |
---|
1771 | |
---|
1772 | /* |
---|
1773 | * Initialize socket's address structure |
---|
1774 | */ |
---|
1775 | isin.sin_family = AF_INET; |
---|
1776 | isin.sin_addr.s_addr = htonl(INADDR_ANY); |
---|
1777 | isin.sin_port = htons(*port); |
---|
1778 | |
---|
1779 | while (bind(*sock, (SOCKADDR *)&isin, sizeof(isin)) == SOCKET_ERROR) { |
---|
1780 | if (LASTERROR == ERRORCODE(EADDRINUSE)) { |
---|
1781 | (*port)++; |
---|
1782 | /* since port is an unsigned short, it may wrap around */ |
---|
1783 | if (*port < IPPORT_RESERVED) |
---|
1784 | *port = IPPORT_RESERVED; |
---|
1785 | isin.sin_port = htons(*port); |
---|
1786 | attempts = 0; |
---|
1787 | } |
---|
1788 | |
---|
1789 | if (attempts++ > MP_MAX_BIND_ATTEMPTS) |
---|
1790 | return MP_Failure; |
---|
1791 | } |
---|
1792 | |
---|
1793 | return MP_Success; |
---|
1794 | } |
---|
1795 | |
---|
1796 | |
---|
1797 | |
---|
1798 | #ifdef __WIN32__ |
---|
1799 | /* |
---|
1800 | * WinSockInitialize calls the WinSock API initialization function WSAStartup |
---|
1801 | * and returns a value != 0 if something went wrong. Extended error information |
---|
1802 | * can be retrieved later by calling WSAGetLastError(); |
---|
1803 | */ |
---|
1804 | #ifdef __STDC__ |
---|
1805 | int WinSockInitialize(void) |
---|
1806 | #else /* __STDC__ */ |
---|
1807 | int WinSockInitialize() |
---|
1808 | #endif /* __STDC__ */ |
---|
1809 | { |
---|
1810 | WORD wVersionRequired; |
---|
1811 | WSADATA wsaData; |
---|
1812 | |
---|
1813 | wVersionRequired = MAKEWORD(1, 1); |
---|
1814 | return WSAStartup(wVersionRequired, &wsaData); |
---|
1815 | } |
---|
1816 | |
---|
1817 | |
---|
1818 | |
---|
1819 | /* |
---|
1820 | * splitargs splits a string of words separated by white-space characters into |
---|
1821 | * multiple strings by inserting Null characters after the ends of the words. |
---|
1822 | * The function returns the number of words found in the string. |
---|
1823 | */ |
---|
1824 | #ifdef __STDC__ |
---|
1825 | static int splitargs(char *argstr) |
---|
1826 | #else /* __STDC__ */ |
---|
1827 | static int splitargs(argstr) |
---|
1828 | char *argstr; |
---|
1829 | #endif /* __STDC__ */ |
---|
1830 | { |
---|
1831 | char *p, *q; |
---|
1832 | int argcnt, wordflag, quoted; |
---|
1833 | |
---|
1834 | p = q = argstr; |
---|
1835 | argcnt = wordflag = quoted = 0; |
---|
1836 | |
---|
1837 | /* Step through all characters in the string. */ |
---|
1838 | while (*p) |
---|
1839 | switch (*p) { |
---|
1840 | /* Is *p a space or a tab character? */ |
---|
1841 | case ' ': |
---|
1842 | case '\t': |
---|
1843 | /* Simply pass it on if it is part of a `quoted` string. */ |
---|
1844 | if (quoted) { |
---|
1845 | *q++ = *p++; |
---|
1846 | break; |
---|
1847 | } |
---|
1848 | |
---|
1849 | /* |
---|
1850 | * If the character marks the end of a word then terminate that |
---|
1851 | * word with a Null character, mark the word as read and increase |
---|
1852 | * the argument counter. |
---|
1853 | */ |
---|
1854 | if (wordflag) { |
---|
1855 | *q++ = '\0'; |
---|
1856 | wordflag = 0; |
---|
1857 | ++argcnt; |
---|
1858 | } |
---|
1859 | p++; |
---|
1860 | break; |
---|
1861 | |
---|
1862 | /* Is *p a backquote character? */ |
---|
1863 | case '`': |
---|
1864 | |
---|
1865 | /* If the next character is another backquote then regard the |
---|
1866 | * combination of both as a single literal backquote and pass it |
---|
1867 | * on to the result string. If not, set the quote mode, i.e. pass |
---|
1868 | * on all following characters until the next backquote is found or |
---|
1869 | * the end of the string reached. |
---|
1870 | */ |
---|
1871 | if (*++p == '`') { |
---|
1872 | *q++ = *p++; |
---|
1873 | wordflag = 1; |
---|
1874 | } else |
---|
1875 | quoted = !quoted; |
---|
1876 | break; |
---|
1877 | |
---|
1878 | /* Put all other characters into the result string. */ |
---|
1879 | default: |
---|
1880 | wordflag = 1; |
---|
1881 | *q++ = *p++; |
---|
1882 | break; |
---|
1883 | } |
---|
1884 | |
---|
1885 | /* Terminate the last word with a Null character. */ |
---|
1886 | if (wordflag) { |
---|
1887 | ++argcnt; |
---|
1888 | *q = '\0'; |
---|
1889 | } |
---|
1890 | |
---|
1891 | return argcnt; |
---|
1892 | } |
---|
1893 | |
---|
1894 | #endif /* __WIN32__ */ |
---|
1895 | |
---|
1896 | |
---|