source: trunk/FACT++/dim/src/tcpip.c@ 13693

Last change on this file since 13693 was 13339, checked in by tbretz, 13 years ago
Updated to v19r31
File size: 33.1 KB
Line 
1/*
2 * DNA (Delphi Network Access) implements the network layer for the DIM
3 * (Delphi Information Managment) System.
4 *
5 * Started : 10-11-91
6 * Last modification : 29-07-94
7 * Written by : C. Gaspar
8 * Adjusted by : G.C. Ballintijn
9 *
10 */
11
12/*
13#define DEBUG
14*/
15
16/* Modifies the number of open connections to 8192 for Windows and Linux */
17/* Can not be moved from here ! */
18#include <dim_tcpip.h>
19
20#ifdef WIN32
21#define ioctl ioctlsocket
22
23#define closesock myclosesocket
24#define readsock recv
25#define writesock send
26
27#define EINTR WSAEINTR
28#define EADDRNOTAVAIL WSAEADDRNOTAVAIL
29#define EWOULDBLOCK WSAEWOULDBLOCK
30#define ECONNREFUSED WSAECONNREFUSED
31#define HOST_NOT_FOUND WSAHOST_NOT_FOUND
32#define NO_DATA WSANO_DATA
33
34#else
35/*
36#define closesock(s) shutdown(s,2)
37*/
38#define closesock(s) close(s)
39#define readsock(a,b,c,d) read(a,b,c)
40
41#if defined(__linux__) && !defined (darwin)
42#define writesock(a,b,c,d) send(a,b,c,MSG_NOSIGNAL)
43#else
44#define writesock(a,b,c,d) write(a,b,c)
45#endif
46
47#ifdef solaris
48#define BSD_COMP
49/*
50#include <thread.h>
51*/
52#endif
53
54#ifdef LYNXOS
55#ifdef RAID
56typedef int pid_t;
57#endif
58#endif
59
60#include <ctype.h>
61#include <sys/socket.h>
62#include <fcntl.h>
63#include <netinet/in.h>
64#include <netinet/tcp.h>
65#include <signal.h>
66#include <sys/ioctl.h>
67#include <errno.h>
68#include <netdb.h>
69
70#endif
71
72#include <stdio.h>
73#include <time.h>
74#define DIMLIB
75#include <dim.h>
76
77#define ushort unsigned short
78
79static int Threads_on = 0;
80
81static int init_done = FALSE; /* Is this module initialized? */
82static int queue_id = 0;
83
84#ifdef WIN32
85static struct sockaddr_in DIM_sockname;
86#endif
87
88static int DIM_IO_path[2] = {-1,-1};
89static int DIM_IO_Done = 0;
90static int DIM_IO_valid = 1;
91
92static int Listen_backlog = SOMAXCONN;
93static int Keepalive_timeout_set = 0;
94static int Write_timeout = WRITE_TMOUT;
95static int Write_timeout_set = 0;
96static int Write_buffer_size = TCP_SND_BUF_SIZE;
97static int Read_buffer_size = TCP_RCV_BUF_SIZE;
98
99int Tcpip_max_io_data_write = TCP_SND_BUF_SIZE - 16;
100int Tcpip_max_io_data_read = TCP_RCV_BUF_SIZE - 16;
101
102void dim_set_listen_backlog(int size)
103{
104 Listen_backlog = size;
105}
106
107int dim_get_listen_backlog()
108{
109 return(Listen_backlog);
110}
111
112void dim_set_keepalive_timeout(int secs)
113{
114 Keepalive_timeout_set = secs;
115}
116
117int dim_get_keepalive_timeout()
118{
119 int ret;
120 extern int get_keepalive_tmout();
121
122 if(!(ret = Keepalive_timeout_set))
123 {
124 ret = get_keepalive_tmout();
125 }
126 return(ret);
127}
128
129void dim_set_write_timeout(int secs)
130{
131 Write_timeout = secs;
132 Write_timeout_set = 1;
133}
134
135int dim_get_write_timeout()
136{
137 int ret;
138 extern int get_write_tmout();
139
140 if(!Write_timeout_set)
141 {
142 if((ret = get_write_tmout()))
143 Write_timeout = ret;
144 }
145 return(Write_timeout);
146}
147
148int dim_set_write_buffer_size(int size)
149{
150 if(size >= TCP_SND_BUF_SIZE)
151 {
152 Write_buffer_size = size;
153 Tcpip_max_io_data_write = size - 16;
154 return(1);
155 }
156 return(0);
157}
158
159int dim_get_write_buffer_size()
160{
161 return(Write_buffer_size);
162}
163
164int dim_set_read_buffer_size(int size)
165{
166 if(size >= TCP_RCV_BUF_SIZE)
167 {
168 Read_buffer_size = size;
169 Tcpip_max_io_data_read = size - 16;
170 return(1);
171 }
172 return(0);
173}
174
175int dim_get_read_buffer_size()
176{
177 return(Read_buffer_size);
178}
179
180#ifdef WIN32
181int init_sock()
182{
183 WORD wVersionRequested;
184 WSADATA wsaData;
185 int err;
186 static int sock_init_done = 0;
187
188 if(sock_init_done) return(1);
189 wVersionRequested = MAKEWORD( 2, 0 );
190 err = WSAStartup( wVersionRequested, &wsaData );
191
192 if ( err != 0 )
193 {
194 return(0);
195 }
196
197 /* Confirm that the WinSock DLL supports 2.0.*/
198 /* Note that if the DLL supports versions greater */
199 /* than 2.0 in addition to 2.0, it will still return */
200 /* 2.0 in wVersion since that is the version we */
201 /* requested. */
202
203 if ( LOBYTE( wsaData.wVersion ) != 2 ||
204 HIBYTE( wsaData.wVersion ) != 0 )
205 {
206 WSACleanup( );
207 return(0);
208 }
209 sock_init_done = 1;
210 return(1);
211}
212
213int myclosesocket(int path)
214{
215 int code, ret;
216 code = WSAGetLastError();
217 ret = closesocket(path);
218 WSASetLastError(code);
219 return ret;
220}
221#endif
222
223int dim_tcpip_init(int thr_flag)
224{
225#ifdef WIN32
226 int addr, flags = 1;
227/*
228 void tcpip_task();
229*/
230 void create_io_thread(void);
231#else
232 struct sigaction sig_info;
233 sigset_t set;
234 void io_sig_handler();
235 void dummy_io_sig_handler();
236 void tcpip_pipe_sig_handler();
237#endif
238 extern int get_write_tmout();
239
240 if(init_done)
241 return(1);
242
243 dim_get_write_timeout();
244#ifdef WIN32
245 init_sock();
246 Threads_on = 1;
247#else
248 if(thr_flag)
249 {
250 Threads_on = 1;
251 }
252 else
253 {
254 sigemptyset(&set);
255
256 sigaddset(&set,SIGALRM);
257 sig_info.sa_handler = io_sig_handler;
258 sig_info.sa_mask = set;
259#ifndef LYNXOS
260 sig_info.sa_flags = SA_RESTART;
261#else
262 sig_info.sa_flags = 0;
263#endif
264
265 if( sigaction(SIGIO, &sig_info, 0) < 0 )
266 {
267 perror( "sigaction(SIGIO)" );
268 exit(1);
269 }
270
271 sigemptyset(&set);
272 sig_info.sa_handler = tcpip_pipe_sig_handler;
273 sig_info.sa_mask = set;
274#ifndef LYNXOS
275 sig_info.sa_flags = SA_RESTART;
276#else
277 sig_info.sa_flags = 0;
278#endif
279
280 if( sigaction(SIGPIPE, &sig_info, 0) < 0 ) {
281 perror( "sigaction(SIGPIPE)" );
282 exit(1);
283 }
284
285 }
286#endif
287 if(Threads_on)
288 {
289#ifdef WIN32
290 if(DIM_IO_path[0] == -1)
291 {
292 if( (DIM_IO_path[0] = socket(AF_INET, SOCK_STREAM, 0)) == -1 )
293 {
294 perror("socket");
295 return(0);
296 }
297
298 DIM_sockname.sin_family = PF_INET;
299 addr = 0;
300 DIM_sockname.sin_addr = *((struct in_addr *) &addr);
301 DIM_sockname.sin_port = htons((ushort) 2000);
302 ioctl(DIM_IO_path[0], FIONBIO, &flags);
303 }
304#else
305 if(DIM_IO_path[0] == -1)
306 {
307 pipe(DIM_IO_path);
308 }
309#endif
310 }
311 if(!queue_id)
312 queue_id = dtq_create();
313
314#ifdef WIN32
315/*
316#ifndef STDCALL
317 tid = _beginthread((void *)(void *)tcpip_task,0,NULL);
318#else
319 tid = _beginthreadex(NULL, NULL,
320 tcpip_task,0,0,NULL);
321#endif
322*/
323 create_io_thread();
324#endif
325 init_done = 1;
326 return(1);
327}
328
329void dim_tcpip_stop()
330{
331#ifdef WIN32
332 closesock(DIM_IO_path[0]);
333#else
334 close(DIM_IO_path[0]);
335 close(DIM_IO_path[1]);
336#endif
337 DIM_IO_path[0] = -1;
338 DIM_IO_path[1] = -1;
339 DIM_IO_Done = 0;
340 init_done = 0;
341}
342
343static int enable_sig(int conn_id)
344{
345 int ret = 1, flags = 1;
346#ifndef WIN32
347 int pid;
348#endif
349
350#ifdef DEBUG
351 if(!Net_conns[conn_id].channel)
352 {
353 printf("Enabling signals on channel 0\n");
354 fflush(stdout);
355 }
356#endif
357
358 if(!init_done)
359 {
360 dim_tcpip_init(0);
361 }
362 if(Threads_on)
363 {
364#ifdef WIN32
365 DIM_IO_valid = 0;
366/*
367 ret = connect(DIM_IO_path[0], (struct sockaddr*)&DIM_sockname, sizeof(DIM_sockname));
368*/
369 closesock(DIM_IO_path[0]);
370 DIM_IO_path[0] = -1;
371 if( (DIM_IO_path[0] = socket(AF_INET, SOCK_STREAM, 0)) == -1 )
372 {
373 perror("socket");
374 return(1);
375 }
376 ret = ioctl(DIM_IO_path[0], FIONBIO, &flags);
377 if(ret != 0)
378 {
379 perror("ioctlsocket");
380 }
381 DIM_IO_valid = 1;
382#else
383 if(DIM_IO_path[1] != -1)
384 {
385 if(!DIM_IO_Done)
386 {
387 DIM_IO_Done = 1;
388 write(DIM_IO_path[1], &flags, 4);
389 }
390 }
391#endif
392 }
393#ifndef WIN32
394 if(!Threads_on)
395 {
396 pid = getpid();
397
398#ifndef __linux__
399 ret = ioctl(Net_conns[conn_id].channel, SIOCSPGRP, &pid );
400#else
401 ret = fcntl(Net_conns[conn_id].channel,F_SETOWN, pid);
402#endif
403 if(ret == -1)
404 {
405#ifdef DEBUG
406 printf("ioctl returned -1\n");
407#endif
408 return(ret);
409 }
410 }
411 ret = ioctl(Net_conns[conn_id].channel, FIOASYNC, &flags );
412 if(ret == -1)
413 {
414#ifdef DEBUG
415 printf("ioctl1 returned -1\n");
416#endif
417 return(ret);
418 }
419
420 flags = fcntl(Net_conns[conn_id].channel,F_GETFD,0);
421#ifdef DEBUG
422 if(flags == -1)
423 {
424 printf("error\n");
425 }
426#endif
427 ret = fcntl(Net_conns[conn_id].channel,F_SETFD, flags | FD_CLOEXEC );
428 if(ret == -1)
429 {
430#ifdef DEBUG
431 printf("ioctl2 returned -1\n");
432#endif
433 return(ret);
434 }
435#endif
436 return(1);
437}
438
439/*
440static void dump_list()
441{
442 int i;
443
444 for( i = 1; i < Curr_N_Conns; i++ )
445 if( Dna_conns[i].busy ) {
446 printf( "dump_list: conn_id=%d reading=%d\n",
447 i, Net_conns[i].reading );
448 }
449}
450*/
451
452static int list_to_fds( fd_set *fds )
453{
454 int i;
455 int found = 0;
456
457 FD_ZERO( fds ) ;
458 for( i = 1; i < Curr_N_Conns; i++ )
459 {
460 if( Dna_conns[i].busy )
461 {
462 if(Net_conns[i].channel)
463 {
464 found = 1;
465 FD_SET( Net_conns[i].channel, fds );
466
467 }
468 }
469 }
470 return(found);
471}
472
473static int fds_get_entry( fd_set *fds, int *conn_id )
474{
475 int i;
476
477 for( i = 1; i < Curr_N_Conns; i++ )
478 {
479 if( Dna_conns[i].busy &&
480 FD_ISSET(Net_conns[i].channel, fds) )
481 {
482 if(Net_conns[i].channel)
483 {
484 *conn_id = i;
485 return 1;
486 }
487 }
488 }
489 return 0;
490}
491
492#if defined(__linux__) && !defined (darwin)
493
494void tcpip_set_keepalive( int channel, int tmout )
495{
496 int val;
497
498 /* Enable keepalive for the given channel */
499 val = 1;
500 setsockopt(channel, SOL_SOCKET, SO_KEEPALIVE, (char*)&val, sizeof(val));
501
502 /* Set the keepalive poll interval to something small.
503 Warning: this section may not be portable! */
504 val = tmout;
505 setsockopt(channel, IPPROTO_TCP, TCP_KEEPIDLE, (char*)&val, sizeof(val));
506 val = 3;
507 setsockopt(channel, IPPROTO_TCP, TCP_KEEPCNT, (char*)&val, sizeof(val));
508 val = tmout/3;
509 setsockopt(channel, IPPROTO_TCP, TCP_KEEPINTVL, (char*)&val, sizeof(val));
510}
511
512#else
513
514static void tcpip_test_write( int conn_id )
515{
516 /* Write to every socket we use, which uses the TCPIP protocol,
517 * which has an established connection (reading), which is currently
518 * not writing data, so we can check if it is still alive.
519 */
520 time_t cur_time;
521
522 if(strcmp(Net_conns[conn_id].node,"MYNODE"))
523 {
524 cur_time = time(NULL);
525 if( cur_time - Net_conns[conn_id].last_used > Net_conns[conn_id].timeout )
526 {
527 dna_test_write( conn_id );
528 }
529 }
530}
531
532#endif
533
534void tcpip_set_test_write(int conn_id, int timeout)
535{
536
537#if defined(__linux__) && !defined (darwin)
538 tcpip_set_keepalive(Net_conns[conn_id].channel, timeout);
539#else
540
541 Net_conns[conn_id].timr_ent = dtq_add_entry( queue_id, timeout,
542 tcpip_test_write, conn_id );
543 Net_conns[conn_id].timeout = timeout;
544 Net_conns[conn_id].last_used = time(NULL);
545
546#endif
547
548}
549
550void tcpip_rem_test_write(int conn_id)
551{
552 if(Net_conns[conn_id].timr_ent)
553 {
554 dtq_rem_entry(queue_id, Net_conns[conn_id].timr_ent);
555 Net_conns[conn_id].timr_ent = NULL;
556 }
557 Net_conns[conn_id].last_used = time(NULL);
558}
559
560void tcpip_pipe_sig_handler( int num )
561{
562 if(num){}
563/*
564 printf( "*** pipe_sig_handler called ***\n" );
565*/
566}
567
568static int get_bytes_to_read(int conn_id)
569{
570 int i, ret, count;
571
572 for(i = 0; i < 3; i++)
573 {
574 ret = ioctl( Net_conns[conn_id].channel, FIONREAD, &count );
575 if( ret != 0)
576 {
577 count = 0;
578 break;
579 }
580 if(count > 0)
581 {
582 break;
583 }
584 }
585 return(count);
586}
587
588static int do_read( int conn_id )
589{
590 /* There is 'data' pending, read it.
591 */
592 int len, totlen, size, count;
593 char *p;
594
595 count = get_bytes_to_read(conn_id);
596 if(!count)
597 {
598/*
599 dna_report_error(conn_id, -1,
600 "Connection closed by remote peer", DIM_ERROR, DIMTCPRDERR);
601 printf("conn_id %d\n", conn_id);
602*/
603 Net_conns[conn_id].read_rout( conn_id, -1, 0 );
604 return 0;
605 }
606
607 size = Net_conns[conn_id].size;
608 p = Net_conns[conn_id].buffer;
609 totlen = 0;
610/*
611 count = 1;
612*/
613 while( size > 0 && count > 0 )
614 {
615/*
616 would this be better? not sure afterwards...
617 nbytes = (size < count) ? size : count;
618 if( (len = readsock(Net_conns[conn_id].channel, p, nbytes, 0)) <= 0 )
619*/
620 if( (len = readsock(Net_conns[conn_id].channel, p, size, 0)) <= 0 )
621 { /* Connection closed by other side. */
622 Net_conns[conn_id].read_rout( conn_id, -1, 0 );
623 return 0;
624 }
625 else
626 {
627
628 /*
629 printf("tcpip: read %d bytes:\n",len);
630 printf( "buffer[0]=%d\n", vtohl((int *)p[0]));
631 printf( "buffer[1]=%d\n", vtohl((int *)p[1]));
632 printf( "buffer[2]=%x\n", vtohl((int *)p[2]));
633 */
634 totlen += len;
635 size -= len;
636 p += len;
637 }
638 if(size)
639 count = get_bytes_to_read(conn_id);
640 }
641
642 Net_conns[conn_id].last_used = time(NULL);
643 Net_conns[conn_id].read_rout( conn_id, 1, totlen );
644 return 1;
645}
646
647
648void do_accept( int conn_id )
649{
650 /* There is a 'connect' pending, serve it.
651 */
652 struct sockaddr_in other;
653 int othersize;
654
655 othersize = sizeof(other);
656 memset( (char *) &other, 0, othersize );
657 Net_conns[conn_id].mbx_channel = accept( Net_conns[conn_id].channel,
658 (struct sockaddr*)&other, (unsigned int *)&othersize );
659 if( Net_conns[conn_id].mbx_channel < 0 )
660 {
661 return;
662 }
663/*
664 else
665 {
666 int all, a, b, c, d;
667 char *pall;
668
669 all = other.sin_addr.s_addr;
670 pall = &all;
671 a = pall[0];
672 a &= 0x000000ff;
673 b = pall[1];
674 b &= 0x000000ff;
675 c = pall[2];
676 c &= 0x000000ff;
677 d = pall[3];
678 d &= 0x000000ff;
679printf("TCPIP got %d.%d.%d.%d \n",
680 a,b,c,d);
681 if((a == 134) && (b == 79) && (c == 157) && (d == 40))
682 {
683 closesock(Net_conns[conn_id].mbx_channel);
684 return;
685 }
686 }
687*/
688
689 Net_conns[conn_id].last_used = time(NULL);
690 Net_conns[conn_id].read_rout( Net_conns[conn_id].mbx_channel,
691 conn_id, TCPIP );
692}
693
694void io_sig_handler(int num)
695{
696 fd_set rfds;
697 int conn_id, ret, selret, count;
698 struct timeval timeout;
699
700 if(num){}
701 do
702 {
703 timeout.tv_sec = 0; /* Don't wait, just poll */
704 timeout.tv_usec = 0;
705 list_to_fds( &rfds );
706 selret = select(FD_SETSIZE, &rfds, NULL, NULL, &timeout);
707 if(selret > 0)
708 {
709 while( (ret = fds_get_entry( &rfds, &conn_id )) > 0 )
710 {
711 if( Net_conns[conn_id].reading )
712 {
713 count = 0;
714 do
715 {
716 if(Net_conns[conn_id].channel)
717 {
718 do_read( conn_id );
719 count = get_bytes_to_read(conn_id);
720 }
721 else
722 {
723 count = 0;
724 }
725 }while(count > 0 );
726 }
727 else
728 {
729 do_accept( conn_id );
730 }
731 FD_CLR( (unsigned)Net_conns[conn_id].channel, &rfds );
732 }
733 }
734 }while(selret > 0);
735}
736
737void tcpip_task( void *dummy)
738{
739 /* wait for an IO signal, find out what is happening and
740 * call the right routine to handle the situation.
741 */
742 fd_set rfds, efds, *pfds;
743 int conn_id, ret, count;
744#ifndef WIN32
745 int data;
746#endif
747 if(dummy){}
748 while(1)
749 {
750 while(!DIM_IO_valid)
751 dim_usleep(1000);
752
753 list_to_fds( &rfds );
754 FD_ZERO(&efds);
755#ifdef WIN32
756 pfds = &efds;
757#else
758 pfds = &rfds;
759#endif
760 FD_SET( DIM_IO_path[0], pfds );
761 ret = select(FD_SETSIZE, &rfds, NULL, &efds, NULL);
762 if(ret > 0)
763 {
764 if(FD_ISSET(DIM_IO_path[0], pfds) )
765 {
766#ifndef WIN32
767 read(DIM_IO_path[0], &data, 4);
768 DIM_IO_Done = 0;
769#endif
770 FD_CLR( (unsigned)DIM_IO_path[0], pfds );
771 }
772/*
773 {
774 DISABLE_AST
775*/
776 while( (ret = fds_get_entry( &rfds, &conn_id )) > 0 )
777 {
778 if( Net_conns[conn_id].reading )
779 {
780 count = 0;
781 do
782 {
783 DISABLE_AST
784 if(Net_conns[conn_id].channel)
785 {
786 do_read( conn_id );
787 count = get_bytes_to_read(conn_id);
788 }
789 else
790 {
791 count = 0;
792 }
793 ENABLE_AST
794 }while(count > 0 );
795 }
796 else
797 {
798 DISABLE_AST
799 do_accept( conn_id );
800 ENABLE_AST
801 }
802 FD_CLR( (unsigned)Net_conns[conn_id].channel, &rfds );
803 }
804/*
805 ENABLE_AST
806 }
807*/
808#ifndef WIN32
809 return;
810#endif
811 }
812 }
813}
814
815int tcpip_start_read( int conn_id, char *buffer, int size, void (*ast_routine)() )
816{
817 /* Install signal handler stuff on the socket, and record
818 * some necessary information: we are reading, and want size
819 * as size, and use buffer.
820 */
821
822 Net_conns[conn_id].read_rout = ast_routine;
823 Net_conns[conn_id].buffer = buffer;
824 Net_conns[conn_id].size = size;
825 if(Net_conns[conn_id].reading == -1)
826 {
827 if(enable_sig( conn_id ) == -1)
828 {
829#ifdef DEBUG
830 printf("START_READ - enable_sig returned -1\n");
831#endif
832 return(0);
833 }
834 }
835 Net_conns[conn_id].reading = TRUE;
836 return(1);
837}
838
839int check_node_addr( char *node, unsigned char *ipaddr)
840{
841unsigned char *ptr;
842int ret;
843
844 ptr = (unsigned char *)node+strlen(node)+1;
845 ipaddr[0] = *ptr++;
846 ipaddr[1] = *ptr++;
847 ipaddr[2] = *ptr++;
848 ipaddr[3] = *ptr++;
849 if( (ipaddr[0] == 0xff) &&
850 (ipaddr[1] == 0xff) &&
851 (ipaddr[2] == 0xff) &&
852 (ipaddr[3] == 0xff) )
853 {
854 errno = ECONNREFUSED; /* fake an error code */
855#ifdef WIN32
856 WSASetLastError(errno);
857#endif
858 return(0);
859 }
860 if( gethostbyaddr(ipaddr, sizeof(ipaddr), AF_INET) == (struct hostent *)0 )
861 {
862#ifndef WIN32
863 ret = h_errno;
864#else
865 ret = WSAGetLastError();
866#endif
867 if((ret == HOST_NOT_FOUND) || (ret == NO_DATA))
868 return(0);
869/*
870 errno = ECONNREFUSED;
871#ifdef WIN32
872 WSASetLastError(errno);
873#endif
874 return(0);
875*/
876 }
877 return(1);
878}
879
880int tcpip_open_client( int conn_id, char *node, char *task, int port )
881{
882 /* Create connection: create and initialize socket stuff. Try
883 * and make a connection with the server.
884 */
885 struct sockaddr_in sockname;
886#ifndef VxWorks
887 struct hostent *host = 0;
888#else
889 int host_addr;
890#endif
891 int path, val, ret_code, ret;
892 int a,b,c,d;
893/* Fix for gcc 4.6 "dereferencing type-punned pointer will break strict-aliasing rules"?!*/
894 unsigned char ipaddr_buff[4];
895 unsigned char *ipaddr = ipaddr_buff;
896 int host_number = 0;
897
898 dim_tcpip_init(0);
899 if(isdigit(node[0]))
900 {
901 sscanf(node,"%d.%d.%d.%d",&a, &b, &c, &d);
902 ipaddr[0] = a;
903 ipaddr[1] = b;
904 ipaddr[2] = c;
905 ipaddr[3] = d;
906 host_number = 1;
907#ifndef VxWorks
908 if( gethostbyaddr(ipaddr, sizeof(ipaddr), AF_INET) == (struct hostent *)0 )
909 {
910#ifndef WIN32
911 ret = h_errno;
912#else
913 ret = WSAGetLastError();
914#endif
915 if((ret == HOST_NOT_FOUND) || (ret == NO_DATA))
916 {
917 if(!check_node_addr(node, ipaddr))
918 return(0);
919 }
920 }
921#endif
922 }
923#ifndef VxWorks
924 else if( (host = gethostbyname(node)) == (struct hostent *)0 )
925 {
926 if(!check_node_addr(node, ipaddr))
927 return(0);
928 host_number = 1;
929/*
930 ptr = (unsigned char *)node+strlen(node)+1;
931 ipaddr[0] = *ptr++;
932 ipaddr[1] = *ptr++;
933 ipaddr[2] = *ptr++;
934 ipaddr[3] = *ptr++;
935 host_number = 1;
936 if( (ipaddr[0] == 0xff) &&
937 (ipaddr[1] == 0xff) &&
938 (ipaddr[2] == 0xff) &&
939 (ipaddr[3] == 0xff) )
940 {
941 errno = ECONNREFUSED;
942#ifdef WIN32
943 WSASetLastError(errno);
944#endif
945 return(0);
946 }
947 if( gethostbyaddr(ipaddr, sizeof(ipaddr), AF_INET) == (struct hostent *)0 )
948 {
949 errno = ECONNREFUSED;
950#ifdef WIN32
951 WSASetLastError(errno);
952#endif
953 return(0);
954 }
955*/
956 }
957#else
958 *(strchr(node,'.')) = '\0';
959 host_addr = hostGetByName(node);
960 printf("node %s addr: %x\n",node, host_addr);
961#endif
962
963 if( (path = socket(AF_INET, SOCK_STREAM, 0)) == -1 )
964 {
965 perror("socket");
966 return(0);
967 }
968
969 val = 1;
970
971 if ((ret_code = setsockopt(path, IPPROTO_TCP, TCP_NODELAY,
972 (char*)&val, sizeof(val))) == -1 )
973 {
974#ifdef DEBUG
975 printf("Couln't set TCP_NODELAY\n");
976#endif
977 closesock(path);
978 return(0);
979 }
980
981 val = Write_buffer_size;
982 if ((ret_code = setsockopt(path, SOL_SOCKET, SO_SNDBUF,
983 (char*)&val, sizeof(val))) == -1 )
984 {
985#ifdef DEBUG
986 printf("Couln't set SO_SNDBUF\n");
987#endif
988 closesock(path);
989 return(0);
990 }
991
992 val = Read_buffer_size;
993 if ((ret_code = setsockopt(path, SOL_SOCKET, SO_RCVBUF,
994 (char*)&val, sizeof(val))) == -1 )
995 {
996#ifdef DEBUG
997 printf("Couln't set SO_RCVBUF\n");
998#endif
999 closesock(path);
1000 return(0);
1001 }
1002
1003#if defined(__linux__) && !defined (darwin)
1004 val = 2;
1005 if ((ret_code = setsockopt(path, IPPROTO_TCP, TCP_SYNCNT,
1006 (char*)&val, sizeof(val))) == -1 )
1007 {
1008#ifdef DEBUG
1009 printf("Couln't set TCP_SYNCNT\n");
1010#endif
1011 }
1012#endif
1013
1014 sockname.sin_family = PF_INET;
1015#ifndef VxWorks
1016 if(host_number)
1017 sockname.sin_addr = *((struct in_addr *) ipaddr);
1018 else
1019 sockname.sin_addr = *((struct in_addr *) host->h_addr);
1020#else
1021 if(host_number)
1022 sockname.sin_addr = *((struct in_addr *) ipaddr);
1023 else
1024 sockname.sin_addr = *((struct in_addr *) &host_addr);
1025#endif
1026 sockname.sin_port = htons((ushort) port); /* port number to send to */
1027 while((ret = connect(path, (struct sockaddr*)&sockname, sizeof(sockname))) == -1 )
1028 {
1029 if(errno != EINTR)
1030 {
1031 closesock(path);
1032 return(0);
1033 }
1034 }
1035 strcpy( Net_conns[conn_id].node, node );
1036 strcpy( Net_conns[conn_id].task, task );
1037 Net_conns[conn_id].channel = path;
1038 Net_conns[conn_id].port = port;
1039 Net_conns[conn_id].last_used = time(NULL);
1040 Net_conns[conn_id].reading = -1;
1041 Net_conns[conn_id].timr_ent = NULL;
1042 Net_conns[conn_id].write_timedout = 0;
1043 return(1);
1044}
1045
1046int tcpip_open_server( int conn_id, char *task, int *port )
1047{
1048 /* Create connection: create and initialize socket stuff,
1049 * find a free port on this node.
1050 */
1051 struct sockaddr_in sockname;
1052 int path, val, ret_code, ret;
1053
1054 dim_tcpip_init(0);
1055 if( (path = socket(AF_INET, SOCK_STREAM, 0)) == -1 )
1056 {
1057 return(0);
1058 }
1059
1060 val = 1;
1061 if ((ret_code = setsockopt(path, IPPROTO_TCP, TCP_NODELAY,
1062 (char*)&val, sizeof(val))) == -1 )
1063
1064 {
1065#ifdef DEBUG
1066 printf("Couln't set TCP_NODELAY\n");
1067#endif
1068 closesock(path);
1069 return(0);
1070 }
1071
1072 val = Write_buffer_size;
1073 if ((ret_code = setsockopt(path, SOL_SOCKET, SO_SNDBUF,
1074 (void *)&val, sizeof(val))) == -1 )
1075 {
1076#ifdef DEBUG
1077 printf("Couln't set SO_SNDBUF\n");
1078#endif
1079 closesock(path);
1080 return(0);
1081 }
1082/*
1083 sval1 = sizeof(val1);
1084 if ((ret_code = getsockopt(path, SOL_SOCKET, SO_SNDBUF,
1085 (void *)&val1, &sval1)) == -1 )
1086 {
1087#ifdef DEBUG
1088 printf("Couln't set SO_SNDBUF\n");
1089#endif
1090 closesock(path);
1091 return(0);
1092 }
1093printf("Set size to %d, got size %d\n", val, val1);
1094*/
1095 val = Read_buffer_size;
1096 if ((ret_code = setsockopt(path, SOL_SOCKET, SO_RCVBUF,
1097 (void *)&val, sizeof(val))) == -1 )
1098 {
1099#ifdef DEBUG
1100 printf("Couln't set SO_RCVBUF\n");
1101#endif
1102 closesock(path);
1103 return(0);
1104 }
1105
1106 if( *port == SEEK_PORT )
1107 { /* Search a free one. */
1108 *port = START_PORT_RANGE - 1;
1109 do
1110 {
1111 (*port)++;
1112 sockname.sin_family = AF_INET;
1113 sockname.sin_addr.s_addr = INADDR_ANY;
1114 sockname.sin_port = htons((ushort) *port);
1115 if( *port > STOP_PORT_RANGE ) {
1116 errno = EADDRNOTAVAIL; /* fake an error code */
1117 closesock(path);
1118#ifdef WIN32
1119 WSASetLastError(errno);
1120#endif
1121 return(0);
1122 }
1123 ret = bind(path, (struct sockaddr*)&sockname, sizeof(sockname));
1124/*
1125printf("Trying port %d, ret = %d\n", *port, ret);
1126*/
1127 } while( ret == -1 );
1128/*
1129 } while( bind(path, (struct sockaddr*)&sockname, sizeof(sockname)) == -1 );
1130*/
1131 } else {
1132#ifndef WIN32
1133 val = 1;
1134 if( setsockopt(path, SOL_SOCKET, SO_REUSEADDR, (char*)&val,
1135 sizeof(val)) == -1 )
1136 {
1137#ifdef DEBUG
1138 printf("Couln't set SO_REUSEADDR\n");
1139#endif
1140 closesock(path);
1141 return(0);
1142 }
1143#endif
1144 sockname.sin_family = AF_INET;
1145 sockname.sin_addr.s_addr = INADDR_ANY;
1146 sockname.sin_port = htons((ushort) *port);
1147 if( (ret = bind(path, (struct sockaddr*) &sockname, sizeof(sockname))) == -1 )
1148 {
1149 closesock(path);
1150 return(0);
1151 }
1152 }
1153
1154 if( (ret = listen(path, Listen_backlog)) == -1 )
1155 {
1156 closesock(path);
1157 return(0);
1158 }
1159
1160 strcpy( Net_conns[conn_id].node, "MYNODE" );
1161 strcpy( Net_conns[conn_id].task, task );
1162 Net_conns[conn_id].channel = path;
1163 Net_conns[conn_id].port = *port;
1164 Net_conns[conn_id].last_used = time(NULL);
1165 Net_conns[conn_id].reading = -1;
1166 Net_conns[conn_id].timr_ent = NULL;
1167 Net_conns[conn_id].write_timedout = 0;
1168 return(1);
1169}
1170
1171
1172int tcpip_start_listen( int conn_id, void (*ast_routine)() )
1173{
1174 /* Install signal handler stuff on the socket, and record
1175 * some necessary information: we are NOT reading, thus
1176 * no size.
1177 */
1178
1179 Net_conns[conn_id].read_rout = ast_routine;
1180 Net_conns[conn_id].size = -1;
1181 if(Net_conns[conn_id].reading == -1)
1182 {
1183 if(enable_sig( conn_id ) == -1)
1184 {
1185#ifdef DEBUG
1186 printf("START_LISTEN - enable_sig returned -1\n");
1187#endif
1188 return(0);
1189 }
1190 }
1191 Net_conns[conn_id].reading = FALSE;
1192 return(1);
1193}
1194
1195
1196int tcpip_open_connection( int conn_id, int path )
1197{
1198 /* Fill in/clear some fields, the node and task field
1199 * get filled in later by a special packet.
1200 */
1201 int val, ret_code;
1202
1203
1204 val = 1;
1205 if ((ret_code = setsockopt(path, IPPROTO_TCP, TCP_NODELAY,
1206 (char*)&val, sizeof(val))) == -1 )
1207 {
1208#ifdef DEBUG
1209 printf("Couln't set TCP_NODELAY\n");
1210#endif
1211 closesock(path);
1212 return(0);
1213 }
1214 val = Write_buffer_size;
1215 if ((ret_code = setsockopt(path, SOL_SOCKET, SO_SNDBUF,
1216 (char*)&val, sizeof(val))) == -1 )
1217 {
1218#ifdef DEBUG
1219 printf("Couln't set SO_SNDBUF\n");
1220#endif
1221 closesock(path);
1222 return(0);
1223 }
1224
1225 val = Read_buffer_size;
1226 if ((ret_code = setsockopt(path, SOL_SOCKET, SO_RCVBUF,
1227 (char*)&val, sizeof(val))) == -1 )
1228 {
1229#ifdef DEBUG
1230 printf("Couln't set SO_RCVBUF\n");
1231#endif
1232 closesock(path);
1233 return(0);
1234 }
1235
1236 Net_conns[conn_id].channel = path;
1237 Net_conns[conn_id].node[0] = 0;
1238 Net_conns[conn_id].task[0] = 0;
1239 Net_conns[conn_id].port = 0;
1240 Net_conns[conn_id].reading = -1;
1241 Net_conns[conn_id].timr_ent = NULL;
1242 Net_conns[conn_id].write_timedout = 0;
1243 return(1);
1244}
1245
1246
1247void tcpip_get_node_task( int conn_id, char *node, char *task )
1248{
1249 strcpy( node, Net_conns[conn_id].node );
1250 strcpy( task, Net_conns[conn_id].task );
1251}
1252
1253int tcpip_write( int conn_id, char *buffer, int size )
1254{
1255 /* Do a (synchronous) write to conn_id.
1256 */
1257 int wrote;
1258
1259 wrote = writesock( Net_conns[conn_id].channel, buffer, size, 0 );
1260 if( wrote == -1 ) {
1261/*
1262 Net_conns[conn_id].read_rout( conn_id, -1, 0 );
1263*/
1264 return(0);
1265 }
1266 return(wrote);
1267}
1268
1269int set_non_blocking(int channel)
1270{
1271 int ret, flags = 1;
1272 ret = ioctl(channel, FIONBIO, &flags );
1273 if(ret == -1)
1274 {
1275#ifdef DEBUG
1276 printf("ioctl non block returned -1\n");
1277#endif
1278 return(ret);
1279 }
1280 return(1);
1281}
1282
1283int set_blocking(int channel)
1284{
1285 int ret, flags = 0;
1286 ret = ioctl(channel, FIONBIO, &flags );
1287 if(ret == -1)
1288 {
1289#ifdef DEBUG
1290 printf("ioctl block returned -1\n");
1291#endif
1292 return(ret);
1293 }
1294 return(1);
1295}
1296
1297int tcpip_write_nowait( int conn_id, char *buffer, int size )
1298{
1299 /* Do a (asynchronous) write to conn_id.
1300 */
1301 int wrote, ret, selret;
1302
1303 struct timeval timeout;
1304 fd_set wfds;
1305 int tcpip_would_block();
1306
1307 set_non_blocking(Net_conns[conn_id].channel);
1308 wrote = writesock( Net_conns[conn_id].channel, buffer, size, 0 );
1309#ifndef WIN32
1310 ret = errno;
1311#else
1312 ret = WSAGetLastError();
1313#endif
1314 set_blocking(Net_conns[conn_id].channel);
1315 if(wrote == -1)
1316 {
1317 if(tcpip_would_block(ret))
1318 {
1319 timeout.tv_sec = Write_timeout;
1320 timeout.tv_usec = 0;
1321 FD_ZERO(&wfds);
1322 FD_SET( Net_conns[conn_id].channel, &wfds);
1323 selret = select(FD_SETSIZE, NULL, &wfds, NULL, &timeout);
1324 if(selret > 0)
1325 {
1326 wrote = writesock( Net_conns[conn_id].channel, buffer, size, 0 );
1327 if( wrote == -1 )
1328 {
1329 return(0);
1330 }
1331 }
1332 }
1333 else
1334 {
1335 return(0);
1336 }
1337 }
1338 if(wrote == -1)
1339 {
1340 Net_conns[conn_id].write_timedout = 1;
1341 }
1342 return(wrote);
1343}
1344
1345int tcpip_close( int conn_id )
1346{
1347 int channel;
1348 /* Clear all traces of the connection conn_id.
1349 */
1350 if(Net_conns[conn_id].timr_ent)
1351 {
1352 dtq_rem_entry(queue_id, Net_conns[conn_id].timr_ent);
1353 Net_conns[conn_id].timr_ent = NULL;
1354 }
1355 channel = Net_conns[conn_id].channel;
1356 Net_conns[conn_id].channel = 0;
1357 Net_conns[conn_id].port = 0;
1358 Net_conns[conn_id].node[0] = 0;
1359 Net_conns[conn_id].task[0] = 0;
1360 if(channel)
1361 {
1362 if(Net_conns[conn_id].write_timedout)
1363 {
1364 Net_conns[conn_id].write_timedout = 0;
1365#if defined(__linux__) && !defined (darwin)
1366 shutdown(channel, 2);
1367#endif
1368 }
1369 closesock(channel);
1370 }
1371 return(1);
1372}
1373
1374
1375int tcpip_failure( int code )
1376{
1377 return(!code);
1378}
1379
1380int tcpip_would_block( int code )
1381{
1382 if(code == EWOULDBLOCK)
1383 return(1);
1384 return(0);
1385}
1386
1387void tcpip_report_error( int code )
1388{
1389#ifndef WIN32
1390 if(code){}
1391 perror("tcpip");
1392#else
1393 int my_perror();
1394
1395 my_perror("tcpip", code);
1396#endif
1397}
1398
1399#ifdef WIN32
1400int my_perror(char *str, int error)
1401{
1402int code;
1403
1404 if(error <= 0)
1405 code = WSAGetLastError();
1406 else
1407 code = error;
1408 printf("new - %s\n",strerror(code));
1409 printf("%s: ",str);
1410 switch(code)
1411 {
1412 case WSAEWOULDBLOCK:
1413 printf("Operation would block");
1414 break;
1415 case WSAEINPROGRESS:
1416 printf("Operation now in progress");
1417 break;
1418 case WSAEALREADY:
1419 printf("Operation already in progress");
1420 break;
1421 case WSAENOTSOCK:
1422 printf("Socket operation on non-socket");
1423 break;
1424 case WSAEDESTADDRREQ:
1425 printf("Destination address required");
1426 break;
1427 case WSAEMSGSIZE:
1428 printf("Message too long");
1429 break;
1430 case WSAEPROTOTYPE:
1431 printf("Protocol wrong type for socket");
1432 break;
1433 case WSAENOPROTOOPT:
1434 printf("Protocol not available");
1435 break;
1436 case WSAEPROTONOSUPPORT:
1437 printf("Protocol not supported");
1438 break;
1439 case WSAESOCKTNOSUPPORT:
1440 printf("Socket type not supported");
1441 break;
1442 case WSAEOPNOTSUPP:
1443 printf("Operation not supported on transport endpoint");
1444 break;
1445 case WSAEPFNOSUPPORT:
1446 printf("Protocol family not supported");
1447 break;
1448 case WSAEAFNOSUPPORT:
1449 printf("Address family not supported by protocol");
1450 break;
1451 case WSAEADDRINUSE:
1452 printf("Address already in use");
1453 break;
1454 case WSAEADDRNOTAVAIL:
1455 printf("Cannot assign requested address");
1456 break;
1457 case WSAENETDOWN:
1458 printf("Network is down");
1459 break;
1460 case WSAENETUNREACH:
1461 printf("Network is unreachable");
1462 break;
1463 case WSAENETRESET:
1464 printf("Network dropped connection because of reset");
1465 break;
1466 case WSAECONNABORTED:
1467 printf("Software caused connection abort");
1468 break;
1469 case WSAECONNRESET:
1470 printf("Connection reset by peer");
1471 break;
1472 case WSAENOBUFS:
1473 printf("No buffer space available");
1474 break;
1475 case WSAEISCONN:
1476 printf("Transport endpoint is already connected");
1477 break;
1478 case WSAENOTCONN:
1479 printf("Transport endpoint is not connected");
1480 break;
1481 case WSAESHUTDOWN:
1482 printf("Cannot send after transport endpoint shutdown");
1483 break;
1484 case WSAETOOMANYREFS:
1485 printf("Too many references: cannot splice");
1486 break;
1487 case WSAETIMEDOUT:
1488 printf("Connection timed out");
1489 break;
1490 case WSAECONNREFUSED:
1491 printf("Connection refused");
1492 break;
1493 case WSAELOOP:
1494 printf("Too many symbolic links encountered");
1495 break;
1496 case WSAENAMETOOLONG:
1497 printf("File name too long");
1498 break;
1499 case WSAEHOSTDOWN:
1500 printf("Host is down");
1501 break;
1502 case WSAEHOSTUNREACH:
1503 printf("No route to host");
1504 break;
1505 case WSAENOTEMPTY:
1506 printf("Directory not empty");
1507 break;
1508 case WSAEUSERS:
1509 printf("Too many users");
1510 break;
1511 case WSAEDQUOT:
1512 printf("Quota exceeded");
1513 break;
1514 case WSAESTALE:
1515 printf("Stale NFS file handle");
1516 break;
1517 case WSAEREMOTE:
1518 printf("Object is remote");
1519 break;
1520 case WSAHOST_NOT_FOUND:
1521 printf("Host not found");
1522 break;
1523 case WSATRY_AGAIN:
1524 printf("Host not found, or SERVERFAIL");
1525 break;
1526 case WSANO_RECOVERY:
1527 printf("Non recoverable errors, FORMERR, REFUSED, NOTIMP");
1528 break;
1529 case WSANO_DATA:
1530 printf("Valid name, no data record of requested type");
1531 break;
1532 default:
1533 printf("Unknown error %d",code);
1534 }
1535 printf("\n");
1536 return(1);
1537}
1538
1539void my_strerror(int error, char *msg)
1540{
1541int code;
1542char str[128];
1543
1544 if(error <= 0)
1545 code = WSAGetLastError();
1546 else
1547 code = error;
1548 switch(code)
1549 {
1550 case WSAEWOULDBLOCK:
1551 sprintf(str,"Operation would block");
1552 break;
1553 case WSAEINPROGRESS:
1554 sprintf(str,"Operation now in progress");
1555 break;
1556 case WSAEALREADY:
1557 sprintf(str,"Operation already in progress");
1558 break;
1559 case WSAENOTSOCK:
1560 sprintf(str,"Socket operation on non-socket");
1561 break;
1562 case WSAEDESTADDRREQ:
1563 sprintf(str,"Destination address required");
1564 break;
1565 case WSAEMSGSIZE:
1566 sprintf(str,"Message too long");
1567 break;
1568 case WSAEPROTOTYPE:
1569 sprintf(str,"Protocol wrong type for socket");
1570 break;
1571 case WSAENOPROTOOPT:
1572 sprintf(str,"Protocol not available");
1573 break;
1574 case WSAEPROTONOSUPPORT:
1575 sprintf(str,"Protocol not supported");
1576 break;
1577 case WSAESOCKTNOSUPPORT:
1578 sprintf(str,"Socket type not supported");
1579 break;
1580 case WSAEOPNOTSUPP:
1581 sprintf(str,"Operation not supported on transport endpoint");
1582 break;
1583 case WSAEPFNOSUPPORT:
1584 sprintf(str,"Protocol family not supported");
1585 break;
1586 case WSAEAFNOSUPPORT:
1587 sprintf(str,"Address family not supported by protocol");
1588 break;
1589 case WSAEADDRINUSE:
1590 sprintf(str,"Address already in use");
1591 break;
1592 case WSAEADDRNOTAVAIL:
1593 sprintf(str,"Cannot assign requested address");
1594 break;
1595 case WSAENETDOWN:
1596 sprintf(str,"Network is down");
1597 break;
1598 case WSAENETUNREACH:
1599 sprintf(str,"Network is unreachable");
1600 break;
1601 case WSAENETRESET:
1602 sprintf(str,"Network dropped connection because of reset");
1603 break;
1604 case WSAECONNABORTED:
1605 sprintf(str,"Software caused connection abort");
1606 break;
1607 case WSAECONNRESET:
1608 sprintf(str,"Connection reset by peer");
1609 break;
1610 case WSAENOBUFS:
1611 sprintf(str,"No buffer space available");
1612 break;
1613 case WSAEISCONN:
1614 sprintf(str,"Transport endpoint is already connected");
1615 break;
1616 case WSAENOTCONN:
1617 sprintf(str,"Transport endpoint is not connected");
1618 break;
1619 case WSAESHUTDOWN:
1620 sprintf(str,"Cannot send after transport endpoint shutdown");
1621 break;
1622 case WSAETOOMANYREFS:
1623 sprintf(str,"Too many references: cannot splice");
1624 break;
1625 case WSAETIMEDOUT:
1626 sprintf(str,"Connection timed out");
1627 break;
1628 case WSAECONNREFUSED:
1629 sprintf(str,"Connection refused");
1630 break;
1631 case WSAELOOP:
1632 sprintf(str,"Too many symbolic links encountered");
1633 break;
1634 case WSAENAMETOOLONG:
1635 sprintf(str,"File name too long");
1636 break;
1637 case WSAEHOSTDOWN:
1638 sprintf(str,"Host is down");
1639 break;
1640 case WSAEHOSTUNREACH:
1641 sprintf(str,"No route to host");
1642 break;
1643 case WSAENOTEMPTY:
1644 sprintf(str,"Directory not empty");
1645 break;
1646 case WSAEUSERS:
1647 sprintf(str,"Too many users");
1648 break;
1649 case WSAEDQUOT:
1650 sprintf(str,"Quota exceeded");
1651 break;
1652 case WSAESTALE:
1653 sprintf(str,"Stale NFS file handle");
1654 break;
1655 case WSAEREMOTE:
1656 sprintf(str,"Object is remote");
1657 break;
1658 case WSAHOST_NOT_FOUND:
1659 sprintf(str,"Host not found");
1660 break;
1661 case WSATRY_AGAIN:
1662 sprintf(str,"Host not found, or SERVERFAIL");
1663 break;
1664 case WSANO_RECOVERY:
1665 sprintf(str,"Non recoverable errors, FORMERR, REFUSED, NOTIMP");
1666 break;
1667 case WSANO_DATA:
1668 sprintf(str,"Valid name, no data record of requested type");
1669 break;
1670 default:
1671 sprintf(str,"Unknown error %d",code);
1672 }
1673 strcpy(msg, str);
1674}
1675#endif
1676
1677void tcpip_get_error( char *str, int code )
1678{
1679 DISABLE_AST
1680#ifndef WIN32
1681 if(code){}
1682 if((errno == ENOENT) && (h_errno == HOST_NOT_FOUND))
1683 strcpy(str,"Host not found");
1684 else
1685 strcpy(str, strerror(errno));
1686#else
1687 my_strerror(code, str);
1688#endif
1689 ENABLE_AST
1690}
Note: See TracBrowser for help on using the repository browser.