home *** CD-ROM | disk | FTP | other *** search
/ ARM Club 3 / TheARMClub_PDCD3.iso / hensa / time / timeserver_2 / c / TimeServer
Text File  |  1999-01-03  |  6KB  |  206 lines

  1. /* c.TimeServer
  2.  *
  3.  * Tserver: Acorn RFC868 Time Server module
  4.  *
  5.  * © Joseph Heenan, 1996-9
  6.  * All rights reserved.
  7.  *
  8.  */
  9.  
  10. #include <stdio.h>
  11. #include <string.h>
  12. #include <time.h>
  13.  
  14. #include "kernel.h"
  15. #include "swis.h"
  16.  
  17. #include "sys/socket.h"
  18. #include "netinet/in.h"
  19. #include "sys/byteorder.h"
  20. #include "sys/errno.h"
  21. #include "sys/ioctl.h"
  22.  
  23. extern int close(int /*s*/);
  24.  
  25. #define TIME_PORT 37
  26.  
  27. static _kernel_oserror inetserver_error = { 0x88000, "*** error ***" };
  28.  
  29. static int timeserver_socket_udp=-1;
  30.  
  31. /* number of event vector */
  32. #define EventV 0x10
  33.  
  34. /* os_byte numbers */
  35. #define EnableEvent 14
  36. #define DisableEvent 13
  37.  
  38. /* event number we're interested in */
  39. #define InternetEvent 19
  40.  
  41. extern int event_entry(_kernel_swi_regs *regs, void *pw); /* CMHG function that calls out inet_event */
  42.  
  43.  
  44. static char *socket_err_string(void)
  45. {
  46.   static char ueb[32];
  47.  
  48.   switch (errno) {
  49.     case 0: return "No error";
  50.     default:
  51.             sprintf(ueb,"Unknown error %d", errno);
  52.             return ueb;
  53.  
  54. case ENOENT               : return "Not found"; /* 2 */
  55. case EBADF                : return "Invalid descriptor"; /* 9 */
  56. case EAGAIN               : return "No more ports"; /* 11 */
  57. case EFAULT               : return "Bad address"; /* 14 */
  58. case EINVAL               : return "Invalid argument"; /* 22 */
  59. case ENOSPC               : return "No space on device/DNS buffer overflow"; /* 28 */
  60. case EPIPE          : return "Broken pipe"; /* 32 */
  61. case EWOULDBLOCK          : return "Operation would block"; /* 35 */
  62. case EINPROGRESS          : return "Operation now in progress"; /* 36 */
  63. case EALREADY             : return "Operation already in progress"; /* 37 */
  64. case ENOTSOCK             : return "Socket operation on non-socket"; /* 38 */
  65. case EDESTADDRREQ         : return "Destination address required"; /* 39 */
  66. case EMSGSIZE             : return "Message too long"; /* 40 */
  67. case EPROTOTYPE           : return "Protocol wrong type for socket";
  68. case ENOPROTOOPT          : return "Protocol not available"; /* 42 */
  69. case EPROTONOSUPPORT      : return "Protocol not supported"; /* 43 */
  70. case ESOCKTNOSUPPORT      : return "Socket type not supported"; /* 44 */
  71. case EOPNOTSUPP           : return "Operation not supported on socket"; /* 45 */
  72. case EPFNOSUPPORT         : return "Protocol family not supported";  /* 46 */
  73. case EAFNOSUPPORT         : return "Address family not supported by protocol family"; /* 47 */
  74. case EADDRINUSE           : return "Address already in use"; /* 48 */
  75. case EADDRNOTAVAIL        : return "Can't assign requested address"; /* 49 */
  76. case ENETDOWN             : return "Network is down"; /*/ 50 */
  77. case ENETUNREACH          : return "Network is unreachable"; /*/ 51 */
  78. case ENETRESET            : return "Network dropped connection on reset"; /*/ 52 */
  79. case ECONNABORTED         : return "Software caused connection abort"; /*/ 53 */
  80. case ECONNRESET           : return "Connection reset by peer"; /*/ 54 */
  81. case ENOBUFS              : return "No buffer space available"; /*/ 55 */
  82. case EISCONN              : return "Socket is already connected"; /*/ 56 */
  83. case ENOTCONN             : return "Socket is not connected"; /*/ 57 */
  84. case ESHUTDOWN            : return "Can't send after socket shutdown"; /*/ 58  */
  85. case ETOOMANYREFS         : return "Too many references: can't splice"; /*/ 59  */
  86. case ETIMEDOUT            : return "Connection timed out"; /*/ 60 */
  87. case ECONNREFUSED         : return "Connection refused"; /*/ 61  */
  88. case EHOSTDOWN            : return "Host is down"; /*/ 64 */
  89. case EHOSTUNREACH         : return "No route to host"; /*/ 65 */
  90. case 486          : return "No internet stack available";
  91.   }
  92. }
  93.  
  94. /* Routine to claim the internet event */
  95. static void register_claim(int claim, void *pw)
  96. {
  97.   _kernel_swi_regs regs;
  98.  
  99.   /* claim event vector */
  100.  
  101.   regs.r[0]= EventV;
  102.   regs.r[1]= (int) event_entry;
  103.   regs.r[2]= (int) pw;
  104.   _kernel_swi(claim ? OS_Claim : OS_Release, ®s, ®s);
  105.  
  106.   /* enable internet event */
  107.   regs.r[0] = claim ? EnableEvent : DisableEvent;
  108.   regs.r[1] = InternetEvent;
  109.   _kernel_swi(OS_Byte, ®s, ®s);
  110. }
  111.  
  112.  
  113. /* Module initialisation routine */
  114. _kernel_oserror *tm_initialise(char *cmd_tail, int podule_base, void *private_word)
  115. {
  116.   struct sockaddr_in serv_addr;
  117.   int flag;
  118.  
  119.   register_claim(1, private_word);
  120.  
  121.   timeserver_socket_udp = socket(PF_INET, SOCK_DGRAM, 0);
  122.   if ( timeserver_socket_udp == -1 )
  123.   {
  124.     strcpy(inetserver_error.errmess,"Could not claim a socket - ");
  125.     goto close_abort;
  126.   }
  127.  
  128.   flag=1;
  129.   ioctl(timeserver_socket_udp, FIOASYNC, &flag); /* Activate internet events */
  130.  
  131.   flag=1;
  132.   ioctl(timeserver_socket_udp, FIONBIO, &flag); /* non-blocking. just in case */
  133.  
  134.   serv_addr.sin_family        = AF_INET;
  135.   serv_addr.sin_port          = htons(TIME_PORT);
  136.   serv_addr.sin_addr.s_addr   = INADDR_ANY;
  137.  
  138.   if ( bind(timeserver_socket_udp, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) == -1 )
  139.   {
  140.     strcpy(inetserver_error.errmess,"Could not bind to time port - ");
  141.     goto close_abort;
  142.   }
  143.  
  144.   return 0;
  145.  
  146.   close_abort:
  147.  
  148.   register_claim(0, private_word);
  149.  
  150.   if (timeserver_socket_udp!=-1)
  151.   {
  152.     close(timeserver_socket_udp);
  153.     timeserver_socket_udp=-1;
  154.   }
  155.   strcat(inetserver_error.errmess, socket_err_string());
  156.   return &inetserver_error;
  157. }
  158.  
  159. /* Module finalisation routine */
  160. _kernel_oserror *tm_finalise(int fatal, int podule, void *pw)
  161. {
  162.   register_claim(0, pw);
  163.  
  164.   if (timeserver_socket_udp!=-1)
  165.     close(timeserver_socket_udp);
  166.  
  167.   return NULL;
  168. }
  169.  
  170. /* Routine called when an internet event occurs */
  171. int inet_event(_kernel_swi_regs *r, void *pw)
  172. {
  173.   struct sockaddr_in client_addr;
  174.   int size = sizeof(client_addr);
  175.   char buf[10];
  176.   time_t now;
  177.   int ret;
  178.  
  179.   if (r->r[2] != timeserver_socket_udp) return 1;
  180.   if (r->r[1] != 1) return 0;
  181.  
  182.   /* New data on our socket. */
  183.  
  184.   ret=recvfrom(timeserver_socket_udp, buf, sizeof(buf), 0, (struct sockaddr *)&client_addr, &size );
  185.  
  186.   if (ret<0)
  187.   {
  188.     /* humbug. error. */
  189.     return 0;
  190.   }
  191.   now = time(NULL);
  192.   now = mktime(gmtime(&now));
  193.   now+=2208988800U; // adjust to secs from 1900, rather than secs from 1970
  194.   {
  195.     char tmp;
  196.     char *buffer=(char *)&now;
  197.     tmp=buffer[2];buffer[2]=buffer[1];buffer[1]=tmp;
  198.     tmp=buffer[3];buffer[3]=buffer[0];buffer[0]=tmp;
  199.   }
  200.  
  201.  
  202.   sendto(timeserver_socket_udp, (char *)&now, sizeof(now), 0, (struct sockaddr *)&client_addr, size);
  203.  
  204.   return 0; /* claim event */
  205. }
  206.