This commit was generated by cvs2svn to track changes on a CVS vendor
[external/binutils.git] / gdb / rdi-share / etherdrv.c
1 /* 
2  * Copyright (C) 1995 Advanced RISC Machines Limited. All rights reserved.
3  * 
4  * This software may be freely used, copied, modified, and distributed
5  * provided that the above copyright notice is preserved in all copies of the
6  * software.
7  */
8
9 /* -*-C-*-
10  *
11  * $Revision$
12  *     $Date$
13  *
14  *
15  * etherdrv.c - Ethernet Driver for Angel.
16  */
17
18 #ifdef __hpux
19 # define _POSIX_SOURCE 1
20 # define _HPUX_SOURCE 1
21 # define _XOPEN_SOURCE 1
22 #endif
23
24 #include <stdio.h>
25 #ifdef __hpux
26 # define uint hide_HPs_uint
27 #endif
28 #ifdef STDC_HEADERS
29 # include <unistd.h>
30 # ifdef __hpux
31 #   undef uint
32 # endif
33 #endif
34 #include <stdlib.h>
35 #include <string.h>
36 #ifdef __hpux
37 # define uint hide_HPs_uint
38 #endif
39 #include <fcntl.h>
40 #ifdef __hpux
41 # undef uint
42 #endif
43 #include <errno.h>
44 #include <stdarg.h>
45 #include <ctype.h>
46 #include "host.h"
47
48 #ifdef COMPILING_ON_WINDOWS
49   typedef char * caddr_t;
50 # undef IGNORE
51 # include <winsock.h>
52 # include "angeldll.h"
53 #else
54 # ifdef __hpux
55 #   define uint hide_HPs_uint
56 # endif
57 # include <sys/types.h>
58 # include <sys/socket.h>
59 # ifdef __hpux
60 #   undef uint
61 # endif
62 # include <netdb.h>
63 # include <sys/time.h>
64 # include <sys/ioctl.h>
65 # ifdef HAVE_SYS_FILIO_H
66 #   include <sys/filio.h>
67 # endif
68 # include <netinet/in.h>
69 # include <arpa/inet.h>
70 #endif
71
72 #include "hsys.h"
73 #include "devices.h"
74 #include "angel_endian.h"
75 #include "buffers.h"
76 #include "hostchan.h"
77 #include "params.h"
78 #include "logging.h"
79 #include "ethernet.h"
80
81
82 #if !defined(COMPILING_ON_WINDOWS) && !defined(STDC_HEADERS)
83 /* These two might not work for windows.  */
84 extern int sys_nerr;
85 extern char * sys_errlist[];
86 #endif
87
88 #ifndef UNUSED
89 # define UNUSED(x) (x = x)      /* Silence compiler warnings */
90 #endif
91
92 /*
93  * forward declarations of static functions
94  */
95 static int EthernetOpen(const char *name, const char *arg);
96 static int EthernetMatch(const char *name, const char *arg);
97 static void EthernetClose(void);
98 static int EthernetRead(DriverCall *dc, bool block);
99 static int EthernetWrite(DriverCall *dc);
100 static int EthernetIoctl(const int opcode, void *args);
101
102 /*
103  * the device descriptor for Ethernet
104  */
105 DeviceDescr angel_EthernetDevice =
106 {
107     "Ethernet",
108     EthernetOpen,
109     EthernetMatch,
110     EthernetClose,
111     EthernetRead,
112     EthernetWrite,
113     EthernetIoctl
114 };
115
116 /*
117  * descriptor for the socket that we talk down
118  */
119 static int sock = -1;
120
121 /*
122  * address of the remote target
123  */
124 static struct sockaddr_in remote, *ia = &remote;
125
126 /*
127  * array of dynamic port numbers on target
128  */
129 static unsigned short int ports[2];
130
131 /*
132  *  Function: set_address
133  *   Purpose: Try to get an address into an understandable form
134  *
135  *    Params:
136  *       Input: addr    The address to parse
137  *
138  *      Output: ia      Structure to hold the parsed address
139  *
140  *   Returns:
141  *          OK:  0
142  *       Error: -1
143  */
144 static int set_address(const char *const addr, struct sockaddr_in *const ia)
145 {
146     ia->sin_family = AF_INET;
147
148     /*
149      * Try address as a dotted decimal
150      */
151     ia->sin_addr.s_addr = inet_addr(addr);
152
153     /*
154      * If that failed, try it as a hostname
155      */
156     if (ia->sin_addr.s_addr == (u_int)-1)
157     {
158         struct hostent *hp = gethostbyname(addr);
159
160         if (hp == NULL)
161             return -1;
162
163         (void)memcpy((caddr_t)&ia->sin_addr, hp->h_addr, hp->h_length);
164     }
165
166     return 0;
167 }
168
169 /*
170  *  Function: open_socket
171  *   Purpose: Open a non-blocking UDP socket, and bind it to a port
172  *              assigned by the system.
173  *
174  *    Params: None
175  *
176  *   Returns:
177  *          OK: socket descriptor
178  *       Error: -1
179  */
180 static int open_socket(void)
181 {
182     int sfd;
183 #if 0                           /* see #if 0 just below -VVV- */
184     int yesplease = 1;
185 #endif
186     struct sockaddr_in local;
187
188     /*
189      * open the socket
190      */
191 #ifdef COMPILING_ON_WINDOWS
192     if ((sfd = socket(AF_INET, SOCK_DGRAM, 0)) == INVALID_SOCKET)
193         return -1;
194 #else
195     if ((sfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
196     {
197 # ifdef DEBUG
198         perror("socket");
199 # endif
200         return -1;
201     }
202 #endif
203
204     /*
205      * 960731 KWelton
206      *
207      * I don't believe that this should be necessary - if we
208      * use select(), then non-blocking I/O is redundant.
209      * Unfortunately, select() appears to be broken (under
210      * Solaris, with a limited amount of time available for
211      * debug), so this code stays in for the time being
212      */
213 #if 0
214     /*
215      * enable non-blocking I/O
216      */
217     if (ioctlsocket(sfd, FIONBIO, &yesplease) < 0)
218     {
219 # ifdef DEBUG
220         perror("ioctl(FIONBIO)");
221 # endif
222         closesocket(sfd);
223
224         return -1;
225     }
226 #endif /* 0/1 */
227
228     /*
229      * bind local address to a system-assigned port
230      */
231     memset((char *)&local, 0, sizeof(local));
232     local.sin_family = AF_INET;
233     local.sin_port = htons(0);
234     local.sin_addr.s_addr = INADDR_ANY;
235     if (bind(sfd, (struct sockaddr *)&local, sizeof(local)) < 0)
236     {
237 #ifdef DEBUG
238         perror("bind");
239 #endif
240         closesocket(sfd);
241
242         return -1;
243     }
244
245     /*
246      * all done
247      */
248     return sfd;
249 }
250
251 /*
252  *  Function: fetch_ports
253  *   Purpose: Request assigned port numbers from remote target
254  *
255  *    Params: None
256  *
257  *   Returns: Nothing
258  *
259  * Post-conditions: This routine will *always* return something for the
260  *                      port numbers.  If the remote target does not
261  *                      respond, then it makes something up - this allows
262  *                      the standard error message (from ardi.c) to be
263  *                      generated when the target is dead for whatever
264  *                      reason.
265  */
266 static void fetch_ports(void)
267 {
268     int i;
269     char ctrlpacket[10];
270     CtrlResponse response;
271
272     memset (ctrlpacket, 0, 10);
273     strcpy (ctrlpacket, CTRL_MAGIC);
274     memset (response, 0, sizeof(CtrlResponse));
275     /*
276      * we will try 3 times to elicit a response from the target
277      */
278     for (i = 0; i < 3; ++i)
279     {
280         struct timeval tv;
281         fd_set fdset;
282
283         /*
284          * send the magic string to the control
285          * port on the remote target
286          */
287         ia->sin_port = htons(CTRL_PORT);
288 #ifdef DEBUG
289         printf("CTLR_PORT=0x%04x  sin_port=0x%04x\n");
290 #endif
291
292         if (sendto(sock, ctrlpacket, sizeof(ctrlpacket), 0,
293                        (struct sockaddr *)ia, sizeof(*ia)) < 0)
294         {
295 #ifdef DEBUG
296             perror("fetch_ports: sendto");
297 #endif
298             return;
299         }
300
301         FD_ZERO(&fdset);
302         FD_SET(sock, &fdset);
303         tv.tv_sec = 0;
304         tv.tv_usec = 250000;
305
306         if (select(sock + 1, &fdset, NULL, NULL, &tv) < 0)
307         {
308 #ifdef DEBUG
309             perror("fetch_ports: select");
310 #endif
311             return;
312         }
313
314         if (FD_ISSET(sock, &fdset))
315         {
316             /*
317              * there is something there - read it
318              */
319             if (recv(sock, (char *)&response, sizeof(response), 0) < 0)
320             {
321 #ifdef COMPILING_ON_WINDOWS
322                 unsigned int werrno = WSAGetLastError();
323
324                 if (werrno == WSAEWOULDBLOCK || werrno == 0)
325 #else
326                 if (errno == EWOULDBLOCK)
327 #endif
328                 {
329                     --i;
330                     continue;
331                 }
332                 else
333                 {
334 #ifdef DEBUG
335                     perror("fetch_ports: recv");
336 #endif
337                     return;
338                 }
339             }
340             {
341                 /*
342                  * XXX
343                  *
344                  * this is *very* unpleasant - try to match the structure
345                  * layout
346                  */
347                 unsigned short *sptr = (unsigned short *)(response + RESP_DBUG);
348
349                 if (strcmp(response, ctrlpacket) == 0)
350                 {
351                     ports[DBUG_INDEX] = htons(*sptr);
352                     sptr++;
353                     ports[APPL_INDEX] = htons(*sptr);
354                 }
355
356 #ifdef DEBUG
357                 printf("fetch_ports: got response, DBUG=%d, APPL=%d\n",
358                        ports[DBUG_INDEX], ports[APPL_INDEX]);
359 #endif
360                 return;
361             }
362         }
363     }
364
365     /*
366      * we failed to get a response
367      */
368 #ifdef DEBUG
369     printf("fetch_ports: failed to get a real answer\n");
370 #endif
371 }
372
373 /*
374  *  Function: read_packet
375  *   Purpose: read a packet, and pass it back to higher levels
376  *
377  *    Params:
378  *      In/Out: packet  Holder for the read packet
379  *
380  *   Returns:  1 - Packet is complete
381  *             0 - No complete packet read
382  *
383  * Post-conditions: Will call panic() if something goes wrong with the OS
384  */
385 static int read_packet(struct data_packet *const packet)
386 {
387     struct sockaddr_in from;
388     int nbytes, fromlen = sizeof(from);
389     DevChanID devchan;
390
391     /*
392      * try to get the packet
393      */
394     if ((nbytes = recvfrom(sock, (char *)(packet->data), packet->buf_len, 0,
395                            (struct sockaddr *)&from, &fromlen)) < 0)
396     {
397 #ifdef COMPILING_ON_WINDOWS
398         if (nbytes == SOCKET_ERROR && WSAGetLastError() != WSAEWOULDBLOCK)
399             MessageBox(GetFocus(), "Error receiving packet\n", "Angel", MB_OK | MB_ICONSTOP);
400 #else
401         if (errno != EWOULDBLOCK)
402         {
403 # ifdef DEBUG
404             perror("recv");
405 # endif
406             panic("ethernet recv failure");
407         }
408 #endif
409         return 0;
410     }
411
412 #ifdef COMPILING_ON_WINDOWS
413     if (pfnProgressCallback != NULL && nbytes != SOCKET_ERROR)
414     {
415         progressInfo.nRead += nbytes;
416         (*pfnProgressCallback)(&progressInfo);
417     }
418 #endif
419
420     /*
421      * work out where the packet was from
422      */
423     if (from.sin_addr.s_addr != remote.sin_addr.s_addr)
424     {
425         /*
426          * not from our target - ignore it
427          */
428 #ifdef DEBUG
429         printf("read_packet: ignoring packet from %s\n",
430                inet_ntoa(from.sin_addr));
431 #endif
432
433         return 0;
434     }
435     else if (ntohs(from.sin_port) == ports[DBUG_INDEX])
436         devchan = DC_DBUG;
437     else if (ntohs(from.sin_port) == ports[APPL_INDEX])
438         devchan = DC_APPL;
439     else
440     {
441         /*
442          * unknown port number - ignore it
443          */
444 #ifdef DEBUG
445         printf("read_packet: ignore packet from port %hd\n",
446                htons(from.sin_port));
447 #endif
448
449         return 0;
450     }
451
452 #if defined(DEBUG) && !defined(DO_TRACE)
453     printf("EthernetRead: %d bytes from %s channel\n",
454            nbytes, (devchan == DC_DBUG) ? "DBUG" : "APPL");
455 #endif
456
457 #ifdef DO_TRACE
458     printf("[%d on %d]\n", nbytes, devchan);
459     {
460         int i = 0;
461         unsigned char *cptr = packet->data;
462
463         while (i < nbytes)
464         {
465             printf("<%02X ", *(cptr++));
466
467             if (!(++i % 16))
468                 printf("\n");
469         }
470
471         if (i % 16)
472             printf("\n");
473     }
474 #endif
475
476     /*
477      * OK - fill in the details
478      */
479     packet->type = devchan;
480     packet->len = nbytes;
481     return 1;
482 }
483
484 /**********************************************************************/
485
486 /*
487  *  Function: Ethernet_Open
488  *   Purpose: Open the Ethernet device.  See the documentation for
489  *              DeviceOpen in drivers.h
490  *
491  * Post-conditions: Will have updated struct sockaddr_in remote (*ia)
492  *                      with the address of the remote target.
493  */
494 static int EthernetOpen(const char *name, const char *arg)
495 {
496 #ifdef COMPILING_ON_WINDOWS
497     WORD wVersionRequested;
498     WSADATA wsaData;
499 #endif
500     /*
501      * name is passed as e=<blah>, so skip 1st two characters
502      */
503     const char *etheraddr = name + 2;
504
505 #ifdef DEBUG
506     printf("EthernetOpen: name `%s'\n", name);
507 #endif
508
509     /* Check that the name is a valid one */
510     if (EthernetMatch(name, arg) != 0)
511         return -1;
512
513 #ifdef COMPILING_ON_WINDOWS
514     wVersionRequested = MAKEWORD(1, 1);
515     if (WSAStartup(wVersionRequested, &wsaData) != 0)
516         /*
517          * Couldn't find a useable winsock.dll.
518          */
519         return -1;
520
521     if ( LOBYTE( wsaData.wVersion ) != 1 || HIBYTE( wsaData.wVersion ) != 1 )
522     {
523         WSACleanup();
524
525         /*
526          * Couldn't find a winsock.dll with supported version.
527          */
528         return -1;
529     }
530 #endif
531
532     memset((char *)ia, 0, sizeof(*ia));
533     if (set_address(etheraddr, ia) < 0)
534     {
535 #ifdef COMPILING_ON_WINDOWS
536         /*
537          * SJ - I'm not sure that this is the correct way to handle this
538          * as Fail calls remote_disable and exits, while panic just exits.
539          * However at the time of writing remote_disable does nothing!
540          */
541  /*     Panic("EthernetOpen: bad name `%s'\n", etheraddr); */
542 #else
543         Fail("EthernetOpen: bad name `%s'\n", etheraddr);
544 #endif
545         return -1;
546     }
547
548     if ((sock = open_socket()) < 0)
549         return -1;
550
551     /*
552      * fetch the port numbers assigned by the remote target
553      * to its Debug and Application sockets
554      */
555     fetch_ports();
556
557     return 0;
558 }
559
560 static int EthernetMatch(const char *name, const char *arg)
561 {
562     /* IGNORE arg */
563     if (0)
564         arg = arg;
565
566     if (name == NULL)
567         return -1;
568
569     if (tolower(name[0]) != 'e' || name[1] != '=')
570         return -1;
571
572     return 0;
573 }
574
575 static void EthernetClose(void)
576 {
577     if (sock >= 0)
578     {
579         closesocket(sock);
580         sock = -1;
581     }
582
583 #ifdef COMPILING_ON_WINDOWS
584     WSACleanup();
585 #endif
586 }
587
588 static int EthernetRead(DriverCall *dc, bool block)
589 {
590     fd_set fdset;
591     struct timeval tv;
592     int err;
593
594     FD_ZERO(&fdset);
595     FD_SET(sock, &fdset);
596
597 #ifdef COMPILING_ON_WINDOWS
598     UNUSED(block);
599     tv.tv_sec = tv.tv_usec = 0;
600 #else
601     tv.tv_sec = 0;
602     tv.tv_usec = (block ? 10000 : 0);
603 #endif
604
605     err = select(sock + 1, &fdset, NULL, NULL, &tv);
606
607     if (err < 0) {
608       if (errno == EINTR) {
609         return 0;
610       }
611       panic("ethernet select failure (errno=%i)",errno);
612       return 0;
613     }
614
615     if (FD_ISSET(sock, &fdset))
616       return read_packet(&dc->dc_packet);
617     else
618       return 0;
619 }
620
621 static int EthernetWrite(DriverCall *dc)
622 {
623     int nbytes;
624     struct data_packet *packet = &dc->dc_packet;
625
626     if (packet->type == DC_DBUG)
627         ia->sin_port = htons(ports[DBUG_INDEX]);
628     else if (packet->type == DC_APPL)
629         ia->sin_port = htons(ports[APPL_INDEX]);
630     else
631     {
632         panic("EthernetWrite: unknown devchan");
633         return 0;
634     }
635
636 #if defined(DEBUG) && !defined(DO_TRACE)
637     printf("EthernetWrite: %d bytes to %s channel\n",
638            packet->len, (packet->type == DC_DBUG) ? "DBUG" : "APPL");
639 #endif
640
641 #ifdef DO_TRACE
642     printf("[%d on %d]\n", packet->len, packet->type);
643     {
644         int i = 0;
645         unsigned char *cptr = packet->data;
646
647         while (i < packet->len)
648         {
649             printf(">%02X ", *(cptr++));
650
651             if (!(++i % 16))
652                 printf("\n");
653         }
654
655         if (i % 16)
656             printf("\n");
657     }
658 #endif
659
660     if ((nbytes = sendto(sock, (char *)(packet->data), packet->len, 0,
661                          (struct sockaddr *)ia, sizeof(*ia))) != packet->len)
662     {
663 #ifdef COMPILING_ON_WINDOWS
664         if (nbytes == SOCKET_ERROR && WSAGetLastError() != WSAEWOULDBLOCK)
665 #else
666         if (nbytes < 0 && errno != EWOULDBLOCK)
667 #endif
668         {
669 #ifdef DEBUG
670             perror("sendto");
671 #endif
672
673 #ifdef COMPILING_ON_WINDOWS
674             panic("ethernet send failure\n");
675 #else
676             /* might not work for Windows */
677             panic("ethernet send failure [%s]\n",
678 #ifdef STDC_HEADERS
679                   strerror(errno));
680 #else
681                   errno < sys_nerr ? sys_errlist[errno] : "unknown errno");
682 #endif /* STDC_HEADERS */
683 #endif
684         }
685 #ifdef DEBUG
686         else if (nbytes >= 0)
687             fprintf(stderr, "ethernet send: asked for %d, sent %d\n", packet->len, nbytes);
688 #endif
689         return 0;
690     }
691
692 #ifdef COMPILING_ON_WINDOWS
693     if (pfnProgressCallback != NULL && nbytes != SOCKET_ERROR)
694     {
695         progressInfo.nWritten += nbytes;
696         (*pfnProgressCallback)(&progressInfo);
697     }
698 #endif
699
700     return 1;
701 }
702
703 static int EthernetIoctl(const int opcode, void *args)
704 {
705 #ifdef DEBUG
706     printf( "EthernetIoctl: op %d arg %x\n", opcode, args );
707 #endif
708
709     /*
710      * IGNORE(opcode)
711      */
712     if (0)
713     {
714         int dummy = opcode;
715         UNUSED(dummy);
716     }
717     UNUSED(args);
718
719     switch ( opcode )
720     {
721         case DC_RESYNC:
722         {
723 #ifdef DEBUG
724             printf( "EthernetIoctl: resync\n" );
725 #endif
726             fetch_ports();
727             return 0;
728         }
729
730         default:
731         {
732             return -1;
733         }
734     }
735 }
736
737 /* EOF etherdrv.c */