home *** CD-ROM | disk | FTP | other *** search
/ PC Online 1997 August / PCO0897.ISO / filesbbs / os2 / plnk065.arj / PLNK065.ZIP / pilot-link.0.6.5 / libsock / socket.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-05-25  |  10.5 KB  |  544 lines

  1. /* socket.c:  Berkeley sockets style interface to Pilot SLP/PADP
  2.  *
  3.  * (c) 1996, D. Jeff Dionne.
  4.  * This is free software, licensed under the GNU Public License V2.
  5.  * See the file COPYING for details.
  6.  */
  7.  
  8. #include <errno.h>
  9. #include <sys/types.h>
  10. #include <sys/stat.h>
  11. #include <stdio.h>
  12. #include <signal.h>
  13. #include <fcntl.h>
  14. #include "pi-source.h"
  15. #include "pi-socket.h"
  16. #include "pi-serial.h"
  17. #include "pi-padp.h"
  18. #include "pi-cmp.h"
  19. #include "pi-dlp.h"
  20. #include "pi-syspkt.h"
  21.  
  22. static struct pi_socket *psl = (struct pi_socket *)0;
  23.  
  24. void installexit(void);
  25.  
  26. extern int dlp_trace;
  27.  
  28. /* Automated tickling interval */
  29. int interval=0;
  30. int busy=0;
  31.  
  32. /* Create a local connection endpoint */
  33.  
  34. int pi_socket(int domain, int type, int protocol)
  35. {
  36.   struct pi_socket *p;
  37.   struct pi_socket *ps;
  38.  
  39.   if ((domain != PI_AF_SLP) ||
  40.       ((type  != PI_SOCK_STREAM) &&
  41.       (type   != PI_SOCK_RAW)) ||
  42.       ((protocol != PI_PF_PADP) &&
  43.        (protocol != PI_PF_SLP))) {  /* FIXME:  Need to support more */
  44.     errno = EINVAL;
  45.     return -1;
  46.   }
  47.  
  48.   ps = malloc(sizeof(struct pi_socket));
  49.   memset(ps,0,sizeof(struct pi_socket));
  50.  
  51. #ifdef OS2
  52.   if((ps->sd = open("NUL", O_RDWR))==-1) {
  53. #else
  54.   if((ps->sd = open("/dev/null", O_RDWR))==-1) {
  55. #endif
  56.     int err = errno; /* Save errno of open */
  57.     free(ps);
  58.     errno = err;
  59.     return -1;
  60.   }
  61.   ps->mac = calloc(1, sizeof(struct pi_mac));
  62.   ps->type = type;
  63.   ps->protocol = protocol;
  64.   ps->connected = 0;
  65.   ps->mac->fd = 0;
  66.   ps->mac->ref = 1;
  67.   ps->xid = 0;
  68.   ps->initiator = 0;
  69.   ps->minorversion = 0;
  70.   ps->majorversion = 0;
  71.   ps->version = 0;
  72.   ps->dlprecord = 0;
  73.   ps->busy = 0;
  74.   
  75. #ifdef OS2
  76.   ps->os2_read_timeout=60;
  77.   ps->os2_write_timeout=60;
  78. #endif
  79.  
  80. #ifndef NO_SERIAL_TRACE
  81.   ps->debuglog = 0;
  82.   ps->debugfd = 0;
  83.   
  84.   if (getenv("PILOTLOG")) {
  85.     if ((ps->debuglog = getenv("PILOTLOGFILE"))==0)
  86.       ps->debuglog = "PiDebug.log";
  87.   }
  88. #endif
  89.  
  90. #ifndef NO_DLP_TRACE
  91.   if (getenv("PILOTDLP")) {
  92.     dlp_trace=1;
  93.   }
  94. #endif
  95.  
  96.   if(type == PI_SOCK_STREAM) {
  97.     ps->establishrate = 9600; /* Default PADP connection rate */
  98.     if (getenv("PILOTRATE"))
  99.         ps->establishrate = atoi(getenv("PILOTRATE"));
  100.     ps->rate = 9600; /* Mandatory CMP conncetion rate */
  101.   } else if(type == PI_SOCK_RAW) {
  102.     ps->establishrate = ps->rate = 57600; /* Mandatory SysPkt connection rate */
  103.   }
  104.   
  105.   installexit();
  106.  
  107.   if (!psl) psl = ps;
  108.   else {
  109.     for (p = psl; p->next; p=p->next);
  110.  
  111.     p->next = ps;
  112.   }
  113.   
  114.   return ps->sd;
  115. }
  116.  
  117. /* Connect to a remote server */
  118.  
  119. int pi_connect(int pi_sd, struct pi_sockaddr *addr, int addrlen)
  120. {
  121.   struct pi_socket *ps;
  122.   struct cmp c;
  123.  
  124.   if (!(ps = find_pi_socket(pi_sd))) {
  125.     errno = ESRCH;
  126.     return -1;
  127.   }
  128.  
  129.   if (pi_device_open(addr->pi_device, ps) == -1) {
  130.     return -1;     /* errno already set */
  131.   }
  132.  
  133.   ps->raddr = *addr;
  134.   ps->laddr = *addr;
  135.    
  136.   if(ps->type == PI_SOCK_STREAM) {
  137.  
  138.     if(cmp_wakeup(ps, 38400)<0) /* Assume this box can't go over 38400 */
  139.       return -1;
  140.  
  141.     if(cmp_rx(ps, &c) < 0)
  142.       return -1; /* failed to read, errno already set */
  143.  
  144.     if(c.type == 2) {
  145.       /* CMP init packet */
  146.  
  147.       if(c.flags & 0x80) {
  148.         /* Change baud rate */
  149.         ps->rate = c.baudrate;
  150.         pi_device_changebaud(ps);
  151.       }
  152.       return 0;
  153.  
  154.     } else if(c.type == 3) {
  155.       /* CMP abort packet -- the other side didn't like us */
  156.       pi_device_close(ps);
  157.  
  158. #ifdef DEBUG
  159.       fprintf(stderr,"Received CMP abort from client\n");
  160. #endif
  161.       errno = -EIO;
  162.       return -1;
  163.     }
  164.   }
  165.   ps->connected = 1;
  166.   
  167.   ps->initiator = 1; /* We initiated the link */
  168.   
  169.   return 0;
  170. }
  171.  
  172. /* Bind address to a local socket */
  173.  
  174. int pi_bind(int pi_sd, struct pi_sockaddr *addr, int addrlen)
  175. {
  176.   struct pi_socket *ps;
  177.  
  178.   if (!(ps = find_pi_socket(pi_sd))) {
  179.     errno = ESRCH;
  180.     return -1;
  181.   }
  182.   
  183.   if (pi_device_open(addr->pi_device, ps) == -1) {
  184.     return -1;     /* errno already set */
  185.   }
  186.   
  187.   ps->laddr = *addr;
  188.   ps->raddr = *addr;
  189.  
  190.   return 0;
  191. }
  192.  
  193. /* Wait for an incoming connection */
  194.  
  195. int pi_listen(int pi_sd, int backlog)
  196. {
  197.   struct pi_socket *ps;
  198.  
  199.   if (!(ps = find_pi_socket(pi_sd))) {
  200.     errno = ESRCH;
  201.     return -1;
  202.   }
  203.   return 0;
  204. }
  205.  
  206. /* Accept an incoming connection */
  207.  
  208. int pi_accept(int pi_sd, struct pi_sockaddr *addr, int *addrlen)
  209. {
  210.   struct pi_socket *ps, *accept;
  211.   struct cmp c;
  212.  
  213.   if (!(ps = find_pi_socket(pi_sd))) {
  214.     errno = ESRCH;
  215.     return -1;
  216.   }
  217.   
  218.   accept = malloc(sizeof(struct pi_socket));
  219.   memcpy(accept, ps, sizeof(struct pi_socket));
  220.  
  221.   if(accept->type == PI_SOCK_STREAM) {
  222.     pi_socket_read(accept, 200);
  223.     if(cmp_rx(accept, &c) < 0)
  224.       goto fail; /* Failed to establish connection, errno already set */
  225.     
  226.     if ((c.version & 0xFF00) == 0x0100) {
  227.       if((unsigned long) accept->establishrate > c.baudrate) {
  228. #ifdef DEBUG
  229.         fprintf(stderr,"Rate %d too high, dropping to %ld\n",ps->establishrate,c.baudrate);
  230. #endif
  231.         accept->establishrate = c.baudrate;
  232.       }
  233.       accept->rate = accept->establishrate;
  234.       accept->version = c.version;
  235.       if(cmp_init(accept, accept->rate)<0)
  236.         goto fail;
  237.       pi_socket_flush(accept);
  238.       if(accept->rate != 9600) {
  239.         pi_device_changebaud(accept);
  240.       }
  241.       accept->connected = 1;
  242.       accept->dlprecord = 0;
  243.     }else {
  244.       cmp_abort(ps, 0x80); /* 0x80 means the comm version wasn't compatible*/
  245.  
  246.       fprintf(stderr, "pi_socket connection failed due to comm version mismatch\n");
  247.       fprintf(stderr, " (expected version 01xx, got %4.4X)\n", c.version);
  248.  
  249.       errno = ECONNREFUSED;
  250.       goto fail;
  251.     }
  252.   } else {
  253.     accept->connected = 1;
  254.   }
  255.   
  256.   accept->sd = dup(ps->sd);
  257.  
  258.   if (!psl) psl = accept;
  259.   else {
  260.     struct pi_socket *p;
  261.     for (p = psl; p->next; p=p->next);
  262.       p->next = accept;
  263.   }
  264.   
  265.   accept->mac->ref++; /* Keep mac around even if the bound socket is closed */
  266.   accept->initiator = 0; /* We accepted the link, we did not initiate it */
  267.   
  268.   return accept->sd;
  269. fail:
  270.   free(accept);
  271.   return -1;
  272. }
  273.  
  274. /* Send msg on a connected socket */
  275.  
  276. int pi_send(int pi_sd, void *msg, int len, unsigned int flags)
  277. {
  278.   struct pi_socket *ps;
  279.  
  280.   if (!(ps = find_pi_socket(pi_sd))) {
  281.     errno = ESRCH;
  282.     return -1;
  283.   }
  284.   
  285.   if (interval)
  286.     alarm(interval);
  287.  
  288.   if(ps->type == PI_SOCK_STREAM) {
  289.     return padp_tx(ps,msg,len,padData);
  290.   } else {
  291.     return syspkt_tx(ps, msg, len);
  292.   }
  293. }
  294.  
  295. /* Recv msg on a connected socket */
  296.  
  297. int pi_recv(int pi_sd, void *msg, int len, unsigned int flags)
  298. {
  299.   struct pi_socket *ps;
  300.  
  301.   if (!(ps = find_pi_socket(pi_sd))) {
  302.     errno = ESRCH;
  303.     return -1;
  304.   }
  305.  
  306.   if(ps->type == PI_SOCK_STREAM) {
  307.     return padp_rx(ps,msg,len);
  308.   } else {
  309.     return syspkt_rx(ps,msg,len);
  310.   }
  311. }
  312.  
  313. /* Wrapper for recv */
  314.  
  315. int pi_read(int pi_sd, void *msg, int len)
  316. {
  317.   return pi_recv(pi_sd, msg, len, 0);
  318. }
  319.  
  320. /* Wrapper for send */
  321.  
  322. int pi_write(int pi_sd, void *msg, int len)
  323. {
  324.   return pi_send(pi_sd, msg, len, 0);
  325. }
  326.  
  327. /* Tickle a stream connection */
  328.  
  329. int pi_tickle(int pi_sd)
  330. {
  331.   struct pi_socket *ps;
  332.  
  333.   if (!(ps = find_pi_socket(pi_sd))) {
  334.     errno = ESRCH;
  335.     return -1;
  336.   }
  337.   
  338.   if(ps->type == PI_SOCK_STREAM) {
  339.     struct padp pd;
  340.     int ret;
  341.     if (ps->busy || !ps->connected)
  342.       return -1;
  343.     pd.type = padTickle;
  344.     pd.flags = 0x00;
  345.     pd.size = 0x00;
  346.     ret = padp_tx(ps, (void *)&pd, 0, padTickle);
  347.     pi_socket_flush(ps);
  348.     return ret;
  349.   }
  350.   else {
  351.     errno = EOPNOTSUPP;
  352.     return -1;
  353.   }
  354. }
  355.  
  356. RETSIGTYPE pi_onalarm(int);
  357.  
  358. int pi_watchdog(int pi_sd, int newinterval)
  359. {
  360.   struct pi_socket *ps;
  361.  
  362.   if (!(ps = find_pi_socket(pi_sd))) {
  363.     errno = ESRCH;
  364.     return -1;
  365.   }
  366.   
  367.   if(ps->type == PI_SOCK_STREAM) {
  368.     ps->tickle = 1;
  369.     signal(SIGALRM, pi_onalarm);
  370.     interval = newinterval;
  371.     alarm(interval);
  372.     return 0;
  373.   } else {
  374.     errno = EOPNOTSUPP;
  375.     return -1;
  376.   }
  377. }
  378.  
  379. /* Close a connection, destroy the socket */
  380.  
  381. int pi_close(int pi_sd)
  382. {
  383.   struct pi_socket *ps;
  384.   struct pi_socket *p;
  385.   
  386.  
  387.   if (!(ps = find_pi_socket(pi_sd))) {
  388.     errno = ESRCH;
  389.     return -1;
  390.   }
  391.   
  392.   busy++;
  393.  
  394.   if (ps->type == PI_SOCK_STREAM) {
  395.     if (ps->connected & 1) /* If socket is connected */
  396.       if (!(ps->connected & 2)) /* And it wasn't end-of-synced */
  397.         dlp_EndOfSync(pi_sd, 0);  /* then end sync, with clean status */
  398.   }
  399.   
  400.   if(ps->sd && (ps->sd != ps->mac->fd)) /* If device still has a /dev/null handle */
  401.     close(ps->sd); /* Close /dev/null handle */
  402.     
  403.   if(ps->mac->fd) { /* If device was opened */
  404.     if (ps->connected) {
  405.       pi_socket_flush(ps); /* Flush the device, and set baud rate back to the initial setting */
  406.       ps->rate = 9600; 
  407.       pi_device_changebaud(ps);
  408.     }
  409.     if (--(ps->mac->ref) == 0) { /* If no-one is using the device, close it */
  410.       pi_device_close(ps);
  411.       free(ps->mac);
  412.     }
  413.   }
  414.  
  415.   if (ps == psl) {
  416.     psl = psl->next;
  417.   } else {
  418.     for (p=psl; p; p=p->next) {
  419.       if (ps == p->next) {
  420.         p->next = p->next->next;
  421.     break;
  422.       }
  423.     }
  424.   }
  425.   
  426.   busy--;
  427.  
  428.   free(ps);
  429.   return 0;
  430. }
  431.  
  432. /* Install an atexit handler that closes open sockets */
  433.  
  434. void pi_onexit(void)
  435. {
  436.   struct pi_socket *p, *n;
  437.   
  438.   for (p=psl; p; p=n ) {
  439.     n = p->next;
  440.     pi_close(p->sd);
  441.   }
  442.   
  443. }
  444.  
  445. RETSIGTYPE pi_onalarm(int signo)
  446. {
  447.   struct pi_socket *p, *n;
  448.   
  449.   signal(SIGALRM,pi_onalarm);
  450.   
  451.   if (busy) {
  452. #ifdef DEBUG
  453.     fprintf(stderr, "world is busy. Rescheduling.\n");
  454. #endif
  455.     alarm(1);
  456.   } else
  457.     for (p=psl; p; p=n ) {
  458.       n = p->next;
  459.       if (p->connected) {
  460. #ifdef DEBUG
  461.         fprintf(stderr, "Tickling socket %d\n", p->sd);
  462. #endif
  463.         if (pi_tickle(p->sd)==-1) {
  464. #ifdef DEBUG
  465.           fprintf(stderr, " but socket is busy. Rescheduling.\n");
  466. #endif
  467.           alarm(1);
  468.         } else
  469.           alarm(interval);
  470.       }
  471.     }
  472. }
  473.  
  474. void installexit(void)
  475. {
  476.   static installedexit = 0;
  477.   
  478.   if (!installedexit)
  479.     atexit(pi_onexit);
  480.     
  481.   installedexit = 1;
  482. }
  483.  
  484. /* Get the local address for a socket */
  485.  
  486. int pi_getsockname(int pi_sd, struct pi_sockaddr * addr, int * namelen)
  487. {
  488.   struct pi_socket *ps;
  489.  
  490.   if (!(ps = find_pi_socket(pi_sd))) {
  491.     errno = ESRCH;
  492.     return -1;
  493.   }
  494.   
  495.   if(addr)
  496.     *addr = ps->laddr;
  497.   if(namelen)
  498.     *namelen = sizeof(struct pi_sockaddr);
  499.     
  500.   return 0;
  501. }
  502.  
  503. /* Get the remote address for a socket */
  504.  
  505. int pi_getsockpeer(int pi_sd, struct pi_sockaddr * addr, int * namelen)
  506. {
  507.   struct pi_socket *ps;
  508.  
  509.   if (!(ps = find_pi_socket(pi_sd))) {
  510.     errno = ESRCH;
  511.     return -1;
  512.   }
  513.   
  514.   if(addr)
  515.     *addr = ps->raddr;
  516.   if(namelen)
  517.     *namelen = sizeof(struct pi_sockaddr);
  518.     
  519.   return 0;
  520. }
  521.  
  522. unsigned int pi_version(int pi_sd)
  523. {
  524.   struct pi_socket *ps;
  525.  
  526.   if (!(ps = find_pi_socket(pi_sd))) {
  527.     errno = ESRCH;
  528.     return -1;
  529.   }
  530.   
  531.   return ps->version;
  532. }
  533.  
  534. struct pi_socket *find_pi_socket(int sd)
  535. {
  536.   struct pi_socket *p;
  537.  
  538.   for (p=psl; p; p=p->next) {
  539.     if (p->sd == sd) return p;
  540.   }
  541.  
  542.   return 0;
  543. }
  544.