home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / nsprpub / pr / src / io / prlayer.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  15.5 KB  |  575 lines

  1. /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2. /*
  3.  * The contents of this file are subject to the Netscape Public License
  4.  * Version 1.0 (the "NPL"); you may not use this file except in
  5.  * compliance with the NPL.  You may obtain a copy of the NPL at
  6.  * http://www.mozilla.org/NPL/
  7.  * 
  8.  * Software distributed under the NPL is distributed on an "AS IS" basis,
  9.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
  10.  * for the specific language governing rights and limitations under the
  11.  * NPL.
  12.  * 
  13.  * The Initial Developer of this code under the NPL is Netscape
  14.  * Communications Corporation.  Portions created by Netscape are
  15.  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
  16.  * Reserved.
  17.  */
  18.  
  19. /*
  20. ** File:        prlayer.c
  21. ** Description: Routines for handling pushable protocol modules on sockets.
  22. */
  23.  
  24. #include "primpl.h"
  25. #include "prerror.h"
  26. #include "prmem.h"
  27. #include "prlock.h"
  28. #include "prlog.h"
  29. #include "prio.h"
  30.  
  31. #include <string.h> /* for memset() */
  32.  
  33. void PR_CALLBACK pl_FDDestructor(PRFileDesc *fd)
  34. {
  35.     PR_ASSERT(fd != NULL);
  36.     if (NULL != fd->lower) fd->lower->higher = fd->higher;
  37.     if (NULL != fd->higher) fd->higher->lower = fd->lower;
  38.     PR_DELETE(fd);
  39. }
  40.  
  41. /*
  42. ** Default methods that just call down to the next fd.
  43. */
  44. static PRStatus PR_CALLBACK pl_TopClose (PRFileDesc *fd)
  45. {
  46.     PRStatus status;
  47.     PR_ASSERT(fd != NULL);
  48.     PR_ASSERT(fd->lower != NULL);
  49.     PR_ASSERT(fd->secret == NULL);
  50.     PR_ASSERT(fd->methods->file_type == PR_DESC_LAYERED);
  51.  
  52.     status = (fd->lower->methods->close)(fd->lower);
  53.  
  54.     fd->dtor(fd);
  55.     return status;
  56. }
  57.  
  58. static PRInt32 PR_CALLBACK pl_DefRead (PRFileDesc *fd, void *buf, PRInt32 amount)
  59. {
  60.     PR_ASSERT(fd != NULL);
  61.     PR_ASSERT(fd->lower != NULL);
  62.  
  63.     return (fd->lower->methods->read)(fd->lower, buf, amount);
  64. }
  65.  
  66. static PRInt32 PR_CALLBACK pl_DefWrite (
  67.     PRFileDesc *fd, const void *buf, PRInt32 amount)
  68. {
  69.     PR_ASSERT(fd != NULL);
  70.     PR_ASSERT(fd->lower != NULL);
  71.  
  72.     return (fd->lower->methods->write)(fd->lower, buf, amount);
  73. }
  74.  
  75. static PRInt32 PR_CALLBACK pl_DefAvailable (PRFileDesc *fd)
  76. {
  77.     PR_ASSERT(fd != NULL);
  78.     PR_ASSERT(fd->lower != NULL);
  79.  
  80.     return (fd->lower->methods->available)(fd->lower);
  81. }
  82.  
  83. static PRInt64 PR_CALLBACK pl_DefAvailable64 (PRFileDesc *fd)
  84. {
  85.     PR_ASSERT(fd != NULL);
  86.     PR_ASSERT(fd->lower != NULL);
  87.  
  88.     return (fd->lower->methods->available64)(fd->lower);
  89. }
  90.  
  91. static PRStatus PR_CALLBACK pl_DefFsync (PRFileDesc *fd)
  92. {
  93.     PR_ASSERT(fd != NULL);
  94.     PR_ASSERT(fd->lower != NULL);
  95.  
  96.     return (fd->lower->methods->fsync)(fd->lower);
  97. }
  98.  
  99. static PRInt32 PR_CALLBACK pl_DefSeek (
  100.     PRFileDesc *fd, PRInt32 offset, PRSeekWhence how)
  101. {
  102.     PR_ASSERT(fd != NULL);
  103.     PR_ASSERT(fd->lower != NULL);
  104.  
  105.     return (fd->lower->methods->seek)(fd->lower, offset, how);
  106. }
  107.  
  108. static PRInt64 PR_CALLBACK pl_DefSeek64 (
  109.     PRFileDesc *fd, PRInt64 offset, PRSeekWhence how)
  110. {
  111.     PR_ASSERT(fd != NULL);
  112.     PR_ASSERT(fd->lower != NULL);
  113.  
  114.     return (fd->lower->methods->seek64)(fd->lower, offset, how);
  115. }
  116.  
  117. static PRStatus PR_CALLBACK pl_DefFileInfo (PRFileDesc *fd, PRFileInfo *info)
  118. {
  119.     PR_ASSERT(fd != NULL);
  120.     PR_ASSERT(fd->lower != NULL);
  121.  
  122.     return (fd->lower->methods->fileInfo)(fd->lower, info);
  123. }
  124.  
  125. static PRStatus PR_CALLBACK pl_DefFileInfo64 (PRFileDesc *fd, PRFileInfo64 *info)
  126. {
  127.     PR_ASSERT(fd != NULL);
  128.     PR_ASSERT(fd->lower != NULL);
  129.  
  130.     return (fd->lower->methods->fileInfo64)(fd->lower, info);
  131. }
  132.  
  133. static PRInt32 PR_CALLBACK pl_DefWritev (PRFileDesc *fd, PRIOVec *iov, PRInt32 size,
  134.                                     PRIntervalTime timeout)
  135. {
  136.     PR_ASSERT(fd != NULL);
  137.     PR_ASSERT(fd->lower != NULL);
  138.  
  139.     return (fd->lower->methods->writev)(fd->lower, iov, size, timeout);
  140. }
  141.  
  142. static PRStatus PR_CALLBACK pl_DefConnect (
  143.     PRFileDesc *fd, const PRNetAddr *addr, PRIntervalTime timeout)
  144. {
  145.     PR_ASSERT(fd != NULL);
  146.     PR_ASSERT(fd->lower != NULL);
  147.  
  148.     return (fd->lower->methods->connect)(fd->lower, addr, timeout);
  149. }
  150.  
  151. static PRFileDesc * PR_CALLBACK pl_TopAccept (
  152.     PRFileDesc *fd, PRNetAddr *addr, PRIntervalTime timeout)
  153. {
  154.     PRFileDesc *newfd;
  155.  
  156.     PR_ASSERT(fd != NULL);
  157.     PR_ASSERT(fd->lower != NULL);
  158.  
  159.     newfd = (fd->lower->methods->accept)(fd->lower, addr, timeout);
  160.     if (newfd != NULL)
  161.     {
  162.         if (PR_FAILURE == PR_PushIOLayer(fd, fd->identity, newfd))
  163.         {
  164.             PR_Close(newfd);
  165.             newfd = NULL;
  166.         }
  167.     }
  168.     return newfd;
  169. }
  170.  
  171. static PRStatus PR_CALLBACK pl_DefBind (PRFileDesc *fd, const PRNetAddr *addr)
  172. {
  173.     PR_ASSERT(fd != NULL);
  174.     PR_ASSERT(fd->lower != NULL);
  175.  
  176.     return (fd->lower->methods->bind)(fd->lower, addr);
  177. }
  178.  
  179. static PRStatus PR_CALLBACK pl_DefListen (PRFileDesc *fd, PRIntn backlog)
  180. {
  181.     PR_ASSERT(fd != NULL);
  182.     PR_ASSERT(fd->lower != NULL);
  183.  
  184.     return (fd->lower->methods->listen)(fd->lower, backlog);
  185. }
  186.  
  187. static PRStatus PR_CALLBACK pl_DefShutdown (PRFileDesc *fd, PRIntn how)
  188. {
  189.     PR_ASSERT(fd != NULL);
  190.     PR_ASSERT(fd->lower != NULL);
  191.  
  192.     return (fd->lower->methods->shutdown)(fd->lower, how);
  193. }
  194.  
  195. static PRInt32 PR_CALLBACK pl_DefRecv (
  196.     PRFileDesc *fd, void *buf, PRInt32 amount,
  197.     PRIntn flags, PRIntervalTime timeout)
  198. {
  199.     PR_ASSERT(fd != NULL);
  200.     PR_ASSERT(fd->lower != NULL);
  201.  
  202.     return (fd->lower->methods->recv)(
  203.         fd->lower, buf, amount, flags, timeout);
  204. }
  205.  
  206. static PRInt32 PR_CALLBACK pl_DefSend (
  207.     PRFileDesc *fd, const void *buf,
  208.     PRInt32 amount, PRIntn flags, PRIntervalTime timeout)
  209. {
  210.     PR_ASSERT(fd != NULL);
  211.     PR_ASSERT(fd->lower != NULL);
  212.  
  213.     return (fd->lower->methods->send)(fd->lower, buf, amount, flags, timeout);
  214. }
  215.  
  216. static PRInt32 PR_CALLBACK pl_DefRecvfrom (
  217.     PRFileDesc *fd, void *buf, PRInt32 amount,
  218.     PRIntn flags, PRNetAddr *addr, PRIntervalTime timeout)
  219. {
  220.     PR_ASSERT(fd != NULL);
  221.     PR_ASSERT(fd->lower != NULL);
  222.  
  223.     return (fd->lower->methods->recvfrom)(
  224.         fd->lower, buf, amount, flags, addr, timeout);
  225. }
  226.  
  227. static PRInt32 PR_CALLBACK pl_DefSendto (
  228.     PRFileDesc *fd, const void *buf, PRInt32 amount, PRIntn flags,
  229.     const PRNetAddr *addr, PRIntervalTime timeout)
  230. {
  231.     PR_ASSERT(fd != NULL);
  232.     PR_ASSERT(fd->lower != NULL);
  233.  
  234.     return (fd->lower->methods->sendto)(
  235.         fd->lower, buf, amount, flags, addr, timeout);
  236. }
  237.  
  238. static PRInt16 PR_CALLBACK pl_DefPoll (PRFileDesc *fd, PRInt16 how_flags)
  239. {
  240.     PR_ASSERT(fd != NULL);
  241.     PR_ASSERT(fd->lower != NULL);
  242.  
  243.     return (fd->lower->methods->poll)(fd->lower, how_flags);
  244. }
  245.  
  246. static PRInt32 PR_CALLBACK pl_DefAcceptread (
  247.     PRFileDesc *sd, PRFileDesc **nd, PRNetAddr **raddr, void *buf,
  248.     PRInt32 amount, PRIntervalTime t)
  249. {
  250.     PR_ASSERT(sd != NULL);
  251.     PR_ASSERT(sd->lower != NULL);
  252.  
  253.     return sd->lower->methods->acceptread(sd->lower, nd, raddr, buf, amount, t);
  254. }
  255.  
  256. static PRInt32 PR_CALLBACK pl_DefTransmitfile (
  257.     PRFileDesc *sd, PRFileDesc *fd, const void *headers, PRInt32 hlen,
  258.     PRTransmitFileFlags flags, PRIntervalTime t)
  259. {
  260.     PR_ASSERT(sd != NULL);
  261.     PR_ASSERT(sd->lower != NULL);
  262.  
  263.     return sd->lower->methods->transmitfile(
  264.         sd->lower, fd, headers, hlen, flags, t);
  265. }
  266.  
  267. static PRStatus PR_CALLBACK pl_DefGetsockname (PRFileDesc *fd, PRNetAddr *addr)
  268. {
  269.     PR_ASSERT(fd != NULL);
  270.     PR_ASSERT(fd->lower != NULL);
  271.  
  272.     return (fd->lower->methods->getsockname)(fd->lower, addr);
  273. }
  274.  
  275. static PRStatus PR_CALLBACK pl_DefGetpeername (PRFileDesc *fd, PRNetAddr *addr)
  276. {
  277.     PR_ASSERT(fd != NULL);
  278.     PR_ASSERT(fd->lower != NULL);
  279.  
  280.     return (fd->lower->methods->getpeername)(fd->lower, addr);
  281. }
  282.  
  283. static PRStatus PR_CALLBACK pl_DefGetsockopt (
  284.     PRFileDesc *fd, PRSockOption optname, void* optval, PRInt32* optlen)
  285. {
  286.     PR_ASSERT(fd != NULL);
  287.     PR_ASSERT(fd->lower != NULL);
  288.  
  289.     return (fd->lower->methods->getsockopt)(fd->lower, optname, optval, optlen);
  290. }
  291.  
  292. static PRStatus PR_CALLBACK pl_DefSetsockopt (
  293.     PRFileDesc *fd, PRSockOption optname, const void* optval, PRInt32 optlen)
  294. {
  295.     PR_ASSERT(fd != NULL);
  296.     PR_ASSERT(fd->lower != NULL);
  297.  
  298.     return (fd->lower->methods->setsockopt)(fd->lower, optname, optval, optlen);
  299. }
  300.  
  301. static PRStatus PR_CALLBACK pl_DefGetsocketoption (
  302.     PRFileDesc *fd, PRSocketOptionData *data)
  303. {
  304.     PR_ASSERT(fd != NULL);
  305.     PR_ASSERT(fd->lower != NULL);
  306.  
  307.     return (fd->lower->methods->getsocketoption)(fd->lower, data);
  308. }
  309.  
  310. static PRStatus PR_CALLBACK pl_DefSetsocketoption (
  311.     PRFileDesc *fd, const PRSocketOptionData *data)
  312. {
  313.     PR_ASSERT(fd != NULL);
  314.     PR_ASSERT(fd->lower != NULL);
  315.  
  316.     return (fd->lower->methods->setsocketoption)(fd->lower, data);
  317. }
  318.  
  319. /* Methods for the top of the stack.  Just call down to the next fd. */
  320. static struct PRIOMethods pl_methods = {
  321.     PR_DESC_LAYERED,
  322.     pl_TopClose,
  323.     pl_DefRead,
  324.     pl_DefWrite,
  325.     pl_DefAvailable,
  326.     pl_DefAvailable64,
  327.     pl_DefFsync,
  328.     pl_DefSeek,
  329.     pl_DefSeek64,
  330.     pl_DefFileInfo,
  331.     pl_DefFileInfo64,
  332.     pl_DefWritev,
  333.     pl_DefConnect,
  334.     pl_TopAccept,
  335.     pl_DefBind,
  336.     pl_DefListen,
  337.     pl_DefShutdown,
  338.     pl_DefRecv,
  339.     pl_DefSend,
  340.     pl_DefRecvfrom,
  341.     pl_DefSendto,
  342.     pl_DefPoll,
  343.     pl_DefAcceptread,
  344.     pl_DefTransmitfile,
  345.     pl_DefGetsockname,
  346.     pl_DefGetpeername,
  347.     pl_DefGetsockopt,
  348.     pl_DefSetsockopt,
  349.     pl_DefGetsocketoption,
  350.     pl_DefSetsocketoption
  351. };
  352.  
  353. PR_IMPLEMENT(PRIOMethods const*) PR_GetDefaultIOMethods()
  354. {
  355.     return &pl_methods;
  356. }  /* PR_GetDefaultIOMethods */
  357.  
  358. PR_IMPLEMENT(PRFileDesc*) PR_CreateIOLayerStub(
  359.     PRDescIdentity ident, PRIOMethods const *methods)
  360. {
  361.     PRFileDesc *fd = NULL;
  362.     PR_ASSERT((PR_NSPR_IO_LAYER != ident) && (PR_TOP_IO_LAYER != ident));
  363.     if ((PR_NSPR_IO_LAYER == ident) || (PR_TOP_IO_LAYER == ident))
  364.         PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
  365.     else
  366.     {
  367.         fd = PR_NEWZAP(PRFileDesc);
  368.         if (NULL == fd)
  369.             PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
  370.         else
  371.         {
  372.             fd->methods = methods;
  373.             fd->dtor = pl_FDDestructor;
  374.             fd->identity = ident;
  375.         }
  376.     }
  377.     return fd;
  378. }  /* PR_CreateIOLayerStub */
  379.  
  380. PR_IMPLEMENT(PRStatus) PR_PushIOLayer(
  381.     PRFileDesc *stack, PRDescIdentity id, PRFileDesc *fd)
  382. {
  383.     PRFileDesc *insert = PR_GetIdentitiesLayer(stack, id);
  384.  
  385.     PR_ASSERT(fd != NULL);
  386.     PR_ASSERT(stack != NULL);
  387.     PR_ASSERT(insert != NULL);
  388.     if ((NULL == stack) || (NULL == fd) || (NULL == insert))
  389.     {
  390.         PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
  391.         return PR_FAILURE;
  392.     }
  393.  
  394.     if (stack == insert)
  395.     {
  396.         /* going on top of the stack */
  397.         PRFileDesc copy = *stack;
  398.         *stack = *fd;
  399.         *fd = copy;
  400.         fd->higher = stack;
  401.         stack->lower = fd;
  402.     }
  403.     else
  404.     {
  405.         /* going somewhere in the middle of the stack */
  406.         fd->lower = insert;
  407.         fd->higher = insert->higher;
  408.  
  409.         insert->higher = fd;
  410.         insert->higher->lower = fd;
  411.     }
  412.  
  413.     return PR_SUCCESS;
  414. }
  415.  
  416. PR_IMPLEMENT(PRFileDesc*) PR_PopIOLayer(PRFileDesc *stack, PRDescIdentity id)
  417. {
  418.     PRFileDesc *extract = PR_GetIdentitiesLayer(stack, id);
  419.  
  420.     PR_ASSERT(0 != id);
  421.     PR_ASSERT(NULL != stack);
  422.     PR_ASSERT(NULL != extract);
  423.     if ((NULL == stack) || (0 == id) || (NULL == extract))
  424.     {
  425.         PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
  426.         return NULL;
  427.     }
  428.  
  429.     if (extract == stack)
  430.     {
  431.         /* popping top layer of the stack */
  432.         PRFileDesc copy = *stack;
  433.         extract = stack->lower;
  434.         *stack = *extract;
  435.         *extract = copy;
  436.         stack->higher = NULL;
  437.     }
  438.     else
  439.     {
  440.         extract->lower->higher = extract->higher;
  441.         extract->higher->lower = extract->lower;
  442.     }
  443.     extract->higher = extract->lower = NULL;
  444.     return extract;
  445. }  /* PR_PopIOLayer */
  446.  
  447. #define ID_CACHE_INCREMENT 16
  448. typedef struct _PRIdentity_cache
  449. {
  450.     PRLock *ml;
  451.     char **name;
  452.     PRIntn length;
  453.     PRDescIdentity ident;
  454. } _PRIdentity_cache;
  455.  
  456. static _PRIdentity_cache identity_cache;
  457.  
  458. PR_IMPLEMENT(PRDescIdentity) PR_GetUniqueIdentity(const char *layer_name)
  459. {
  460.     PRDescIdentity identity, length;
  461.     char **names = NULL, *name = NULL, **old = NULL;
  462.  
  463.     if (!_pr_initialized) _PR_ImplicitInitialization();
  464.  
  465.     PR_ASSERT((PRDescIdentity)0x7fff > identity_cache.ident);
  466.  
  467.     if (NULL != layer_name)
  468.     {
  469.         name = (char*)PR_Malloc(strlen(layer_name) + 1);
  470.         if (NULL == name)
  471.         {
  472.             PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
  473.             return PR_INVALID_IO_LAYER;
  474.         }
  475.         strcpy(name, layer_name);
  476.     }
  477.  
  478.     /* this initial code runs unsafe */
  479. retry:
  480.     PR_ASSERT(NULL == names);
  481.     length = identity_cache.length;
  482.     if (length < (identity_cache.ident + 1))
  483.     {
  484.         length += ID_CACHE_INCREMENT;
  485.         names = (char**)PR_CALLOC(length * sizeof(char*));
  486.         if (NULL == names)
  487.         {
  488.             if (NULL != name) PR_DELETE(name);
  489.             PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
  490.             return PR_INVALID_IO_LAYER;
  491.         }
  492.     }
  493.  
  494.     /* now we get serious about thread safety */
  495.     PR_Lock(identity_cache.ml);
  496.     PR_ASSERT(identity_cache.ident <= identity_cache.length);
  497.     identity = identity_cache.ident + 1;
  498.     if (identity > identity_cache.length)  /* there's no room */
  499.     {
  500.         /* we have to do something - hopefully it's already done */
  501.         if ((NULL != names) && (length >= identity))
  502.         {
  503.             /* what we did is still okay */
  504.             memcpy(
  505.                 names, identity_cache.name,
  506.                 identity_cache.length * sizeof(char*));
  507.             old = identity_cache.name;
  508.             identity_cache.name = names;
  509.             identity_cache.length = length;
  510.             names = NULL;
  511.         }
  512.         else
  513.         {
  514.             PR_ASSERT(identity_cache.ident <= identity_cache.length);
  515.             PR_Unlock(identity_cache.ml);
  516.             if (NULL != names) PR_DELETE(names);
  517.             goto retry;
  518.         }
  519.     }
  520.     if (NULL != name) /* there's a name to be stored */
  521.     {
  522.         identity_cache.name[identity] = name;
  523.     }
  524.     identity_cache.ident = identity;
  525.     PR_ASSERT(identity_cache.ident <= identity_cache.length);
  526.     PR_Unlock(identity_cache.ml);
  527.  
  528.     if (NULL != old) PR_DELETE(old);
  529.     if (NULL != names) PR_DELETE(names);
  530.  
  531.     return identity;
  532. }  /* PR_GetUniqueIdentity */
  533.  
  534. PR_IMPLEMENT(const char*) PR_GetNameForIdentity(PRDescIdentity ident)
  535. {
  536.     if (!_pr_initialized) _PR_ImplicitInitialization();
  537.  
  538.     if (PR_TOP_IO_LAYER == ident) return NULL;
  539.  
  540.     PR_ASSERT(ident <= identity_cache.ident);
  541.     return (ident > identity_cache.ident) ? NULL : identity_cache.name[ident];
  542. }  /* PR_GetNameForIdentity */
  543.  
  544. PR_IMPLEMENT(PRDescIdentity) PR_GetLayersIdentity(PRFileDesc* fd)
  545. {
  546.     PR_ASSERT(NULL != fd);
  547.     return fd->identity;
  548. }  /* PR_GetLayersIdentity */
  549.  
  550. PR_IMPLEMENT(PRFileDesc*) PR_GetIdentitiesLayer(PRFileDesc* fd, PRDescIdentity id)
  551. {
  552.     PRFileDesc *layer = fd;
  553.  
  554.     if (PR_TOP_IO_LAYER == id) return fd;
  555.  
  556.     for (layer = fd; layer != NULL; layer = layer->lower)
  557.     {
  558.         if (id == layer->identity) return layer;
  559.     }
  560.     for (layer = fd; layer != NULL; layer = layer->higher)
  561.     {
  562.         if (id == layer->identity) return layer;
  563.     }
  564.     return NULL;
  565. }  /* PR_GetIdentitiesLayer */
  566.  
  567. void _PR_InitLayerCache()
  568. {
  569.     memset(&identity_cache, 0, sizeof(identity_cache));
  570.     identity_cache.ml = PR_NewLock();
  571.     PR_ASSERT(NULL != identity_cache.ml);
  572. }  /* _PR_InitLayerCache */
  573.  
  574. /* prlayer.c */
  575.