int main(void)
{
	Error1();
	Error2();
	Error3();
	Error4();
	Error6();
	printf("Pareciera que esta todo bien!!\n");
}
Beispiel #2
0
/* retrieve the OPEN group options and perform the open() call.
   returns the file descriptor or a negative value.
   Applies options of phases PREOPEN, OPEN, PASTOPEN, and FD
*/
int _xioopen_open(const char *path, int rw, struct opt *opts) {
   mode_t mode = 0666;
   flags_t flags = rw;
   bool flag;
   int fd;

   applyopts_named(path, opts, PH_PREOPEN);

   /* this only applies pure OPEN flags, not mixed OPEN/FCNTL options */
   applyopts_flags(opts, GROUP_OPEN, &flags);

   /* we have to handle mixed OPEN/FCNTL flags specially */
   if (retropt_bool(opts, OPT_O_APPEND, &flag) >= 0   && flag)
      flags |= O_APPEND;
   if (retropt_bool(opts, OPT_O_NONBLOCK, &flag) >= 0 && flag)
      flags |= O_NONBLOCK;
#ifdef O_ASYNC
   if (retropt_bool(opts, OPT_O_ASYNC, &flag) >= 0    && flag)
      flags |= O_ASYNC;
#endif
   if (retropt_bool(opts, OPT_O_TRUNC, &flag) >= 0  && flag)
      flags |= O_TRUNC;
#ifdef O_BINARY
   if (retropt_bool(opts, OPT_O_BINARY,    &flag) >= 0   && flag)
      flags |= O_BINARY;
#endif
#ifdef O_TEXT
   if (retropt_bool(opts, OPT_O_TEXT,      &flag) >= 0   && flag)
      flags |= O_TEXT;
#endif
#ifdef O_NOINHERIT
   if (retropt_bool(opts, OPT_O_NOINHERIT, &flag) >= 0   && flag)
      flags |= O_NOINHERIT;
#endif
#ifdef O_NOATIME
   if (retropt_bool(opts, OPT_O_NOATIME,   &flag) >= 0   && flag)
      flags |= O_NOATIME;
#endif

   retropt_modet(opts, OPT_PERM,      &mode);

   if ((fd = Open(path, flags, mode)) < 0) {
      Error4("open(\"%s\", 0%lo, 0%03o): %s",
	     path, flags, mode, strerror(errno));
      return STAT_RETRYLATER;
   }
   /*0 Info4("open(\"%s\", 0%o, 0%03o) -> %d", path, flags, mode, fd);*/
   applyopts_named(path, opts, PH_PASTOPEN);
#if 0
   applyopts_named(path, opts, PH_FD);
   applyopts(fd, opts, PH_FD);
   applyopts_cloexec(fd, opts);
#endif
   return fd;
}
Beispiel #3
0
/* returns 0 if it could create lock; 1 if the lock exists; -1 on error */
int xiogetlock(const char *lockfile) {
   char *s;
   struct stat strat;
   int fd;
   pid_t pid;
   char pidbuf[3*sizeof(pid_t)+1];
   size_t bytes;

   if (Lstat(lockfile, &strat) == 0) {
      return 1;
   }
   switch (errno) {
   case ENOENT: break;
   default:
      Error3("Lstat(\"%s\", %p): %s", lockfile, &strat, strerror(errno));
      return -1;
   }
   /* in this moment, the file did not exist */

   if ((s = Malloc(strlen(lockfile)+8)) == NULL) {
      errno = ENOMEM;
      return -1;
   }
   strcpy(s, lockfile);
   strcat(s, ".XXXXXX");

   if ((fd = Mkstemp(s)) < 0) {
      Error2("mkstemp(\"%s\"): %s", s, strerror(errno));
      return -1;
   }
  
   pid = Getpid();
   bytes = sprintf(pidbuf, F_pid, pid);
   if (writefull(fd, pidbuf, bytes) < 0) {
      Error4("write(%d, %p, "F_Zu"): %s", fd, pidbuf, bytes, strerror(errno));
      return -1;
   }
   Close(fd);

   /* Chmod(lockfile, 0600); */
   if (Link(s, lockfile) < 0) {
      int _errno = errno;
      Error3("link(\"%s\", \"%s\"): %s", s, lockfile, strerror(errno));
      Unlink(s);
      errno = _errno;
      return -1;
   }
   Unlink(s);

   return 0;
}
Beispiel #4
0
void Tribe::Unbuild(NPC* npc, gemNPCItem* building)
{
    NPCDebug(npc, 6, "Unbuilding building %s",building->GetName());

    Asset* buildingAsset = GetAsset(building);
    if(buildingAsset)
    {
        buildingAsset->status = ASSET_STATUS_NOT_USED;
        buildingAsset->quantity = 0;
        SaveAsset(buildingAsset);

        // Check if there is a building spot that need to be downgrades as well
        csVector3 buildingPos = npc->GetTribe()->GetHomePosition();

        buildingPos -= buildingAsset->pos;

        Asset* buildingSpot = GetNearestAsset(Tribe::ASSET_TYPE_BUILDINGSPOT, buildingAsset->name, Tribe::ASSET_STATUS_CONSTRUCTED,
                                              buildingPos, NULL, 5.0, NULL);
        if(buildingSpot)
        {
            buildingSpot->status = Tribe::ASSET_STATUS_NOT_USED;
            SaveAsset(buildingSpot);

            // Now the building asset and the spot is freed inform the server
            npcclient->GetNetworkMgr()->QueueUnbuildCommand(npc->GetActor(), building);
        }
        else
        {
            Error4("NPC %s(%s) Failed to find building spot for building %s",npc->GetName(),ShowID(npc->GetEID()),building->GetName());
        }
    }
    else
    {
        Error4("NPC %s(%s) Failed to find building asset for building %s",npc->GetName(),ShowID(npc->GetEID()),building->GetName());
    }
}
Beispiel #5
0
/* we expect the form: port */
int xioopen_ipdgram_listen(int argc, const char *argv[], struct opt *opts,
			   int xioflags, xiofile_t *fd,
			  unsigned groups, int pf, int ipproto,
			  int protname) {
   const char *portname = argv[1];
   union sockaddr_union us;
   union sockaddr_union themunion;
   union sockaddr_union *them = &themunion;
   int socktype = SOCK_DGRAM;
   struct pollfd readfd;
   bool dofork = false;
   pid_t pid;
   char *rangename;
   char infobuff[256];
   unsigned char buff1[1];
   socklen_t uslen;
   socklen_t themlen;
   int result;

   if (argc != 2) {
      Error2("%s: wrong number of parameters (%d instead of 1)", argv[0], argc-1);
   }

   if (pf == PF_UNSPEC) {
#if WITH_IP4 && WITH_IP6
      pf = xioopts.default_ip=='6'?PF_INET6:PF_INET;
#elif WITH_IP6
      pf = PF_INET6;
#else
      pf = PF_INET;
#endif
   }

   retropt_socket_pf(opts, &pf);

   if (applyopts_single(&fd->stream, opts, PH_INIT) < 0)  return -1;
   applyopts(-1, opts, PH_INIT);

   uslen = socket_init(pf, &us);
   retropt_bind(opts, pf, socktype, IPPROTO_UDP,
		(struct sockaddr *)&us, &uslen, 1,
		fd->stream.para.socket.ip.res_opts[1],
		fd->stream.para.socket.ip.res_opts[0]);

   if (false) {
      ;
#if WITH_IP4
   } else if (pf == PF_INET) {
      us.ip4.sin_port = parseport(portname, ipproto);
#endif
#if WITH_IP6
   } else if (pf == PF_INET6) {
      us.ip6.sin6_port = parseport(portname, ipproto);
#endif
   } else {
      Error1("xioopen_ipdgram_listen(): unknown address family %d", pf);
   }

   retropt_bool(opts, OPT_FORK, &dofork);

   if (dofork) {
      if (!(xioflags & XIO_MAYFORK)) {
	 Error("option fork not allowed here");
	 return STAT_NORETRY;
      }
   }

#if WITH_IP4 /*|| WITH_IP6*/
   if (retropt_string(opts, OPT_RANGE, &rangename) >= 0) {
      if (xioparserange(rangename, pf, &fd->stream.para.socket.range) < 0) {
	 free(rangename);
	 return STAT_NORETRY;
      }
      free(rangename);
      fd->stream.para.socket.dorange = true;
   }
#endif

#if WITH_LIBWRAP
   xio_retropt_tcpwrap(&fd->stream, opts);
#endif /* WITH_LIBWRAP */

   if (retropt_ushort(opts, OPT_SOURCEPORT, &fd->stream.para.socket.ip.sourceport)
       >= 0) {
      fd->stream.para.socket.ip.dosourceport = true;
   }
   retropt_bool(opts, OPT_LOWPORT, &fd->stream.para.socket.ip.lowport);

   if (dofork) {
      xiosetchilddied();	/* set SIGCHLD handler */
   }

   while (true) {	/* we loop with fork or prohibited packets */
      /* now wait for some packet on this datagram socket, get its sender
	 address, connect there, and return */
      int one = 1;
      char infobuff[256];
      union sockaddr_union _sockname;
      union sockaddr_union *la = &_sockname;	/* local address */

      if ((fd->stream.fd = xiosocket(opts, pf, socktype, ipproto, E_ERROR)) < 0) {
	 return STAT_RETRYLATER;
      }
      applyopts(fd->stream.fd, opts, PH_PASTSOCKET);
      if (Setsockopt(fd->stream.fd, opt_so_reuseaddr.major,
		     opt_so_reuseaddr.minor, &one, sizeof(one)) < 0) {
	 Warn6("setsockopt(%d, %d, %d, {%d}, "F_Zd"): %s",
	       fd->stream.fd, opt_so_reuseaddr.major,
	       opt_so_reuseaddr.minor, one, sizeof(one), strerror(errno));
      }
      applyopts_cloexec(fd->stream.fd, opts);
      applyopts(fd->stream.fd, opts, PH_PREBIND);
      applyopts(fd->stream.fd, opts, PH_BIND);
      if (Bind(fd->stream.fd, &us.soa, uslen) < 0) {
	 Error4("bind(%d, {%s}, "F_Zd"): %s", fd->stream.fd,
		sockaddr_info(&us.soa, uslen, infobuff, sizeof(infobuff)),
		uslen, strerror(errno));
	 return STAT_RETRYLATER;
      }
      /* under some circumstances bind() fills sockaddr with interesting info. */
      if (Getsockname(fd->stream.fd, &us.soa, &uslen) < 0) {
	 Error4("getsockname(%d, %p, {%d}): %s",
		fd->stream.fd, &us.soa, uslen, strerror(errno));
      }
      applyopts(fd->stream.fd, opts, PH_PASTBIND);

      Notice1("listening on UDP %s",
	      sockaddr_info(&us.soa, uslen, infobuff, sizeof(infobuff)));
      readfd.fd = fd->stream.fd;
      readfd.events = POLLIN|POLLERR;
      while (xiopoll(&readfd, 1, NULL) < 0) {
	 if (errno != EINTR)  break;
      }

      themlen = socket_init(pf, them);
      do {
	 result = Recvfrom(fd->stream.fd, buff1, 1, MSG_PEEK,
			     &them->soa, &themlen);
      } while (result < 0 && errno == EINTR);
      if (result < 0) {
	 Error5("recvfrom(%d, %p, 1, MSG_PEEK, {%s}, {"F_Zu"}): %s",
		fd->stream.fd, buff1,
		sockaddr_info(&them->soa, themlen, infobuff, sizeof(infobuff)),
		themlen, strerror(errno));
	 return STAT_RETRYLATER;
      }

      Notice1("accepting UDP connection from %s",
	      sockaddr_info(&them->soa, themlen, infobuff, sizeof(infobuff)));

      if (xiocheckpeer(&fd->stream, them, la) < 0) {
	 /* drop packet */
	 char buff[512];
	 Recv(fd->stream.fd, buff, sizeof(buff), 0);	/* drop packet */
	 Close(fd->stream.fd);
	 continue;
      }
      Info1("permitting UDP connection from %s",
	    sockaddr_info(&them->soa, themlen, infobuff, sizeof(infobuff)));

      if (dofork) {
	 pid = xio_fork(false, E_ERROR);
	 if (pid < 0) {
	    return STAT_RETRYLATER;
	 }

	 if (pid == 0) {	/* child */
	    break;
	 }

	 /* server: continue loop with socket()+recvfrom() */
	 /* when we dont close this we get awkward behaviour on Linux 2.4:
	    recvfrom gives 0 bytes with invalid socket address */
	 if (Close(fd->stream.fd) < 0) {
	    Info2("close(%d): %s", fd->stream.fd, strerror(errno));
	 }
	 Sleep(1);	/*! give child a chance to consume the old packet */

	 continue;
      }
      break;
   }

   applyopts(fd->stream.fd, opts, PH_CONNECT);
   if ((result = Connect(fd->stream.fd, &them->soa, themlen)) < 0) {
      Error4("connect(%d, {%s}, "F_Zd"): %s",
	     fd->stream.fd,
	     sockaddr_info(&them->soa, themlen, infobuff, sizeof(infobuff)),
	     themlen, strerror(errno));
      return STAT_RETRYLATER;
   }

   /* set the env vars describing the local and remote sockets */
   if (Getsockname(fd->stream.fd, &us.soa, &uslen) < 0) {
      Warn4("getsockname(%d, %p, {%d}): %s",
	    fd->stream.fd, &us.soa, uslen, strerror(errno));
   }
   xiosetsockaddrenv("SOCK", &us,  uslen,   IPPROTO_UDP);
   xiosetsockaddrenv("PEER", them, themlen, IPPROTO_UDP);

   fd->stream.howtoend = END_SHUTDOWN;
   applyopts_fchown(fd->stream.fd, opts);
   applyopts(fd->stream.fd, opts, PH_LATE);

   if ((result = _xio_openlate(&fd->stream, opts)) < 0)
      return result;

   return 0;
}
Beispiel #6
0
static int xioopen_tun(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *xfd, unsigned groups, int dummy1, int dummy2, int dummy3) {
   char *tundevice = NULL;
   char *tunname = NULL, *tuntype = NULL;
   int pf = /*! PF_UNSPEC*/ PF_INET;
   struct xiorange network;
   bool no_pi = false;
   const char *namedargv[] = { "tun", NULL, NULL };
   int rw = (xioflags & XIO_ACCMODE);
   bool exists;
   struct ifreq ifr;
   int sockfd;
   char *ifaddr;
   int result;

   if (argc > 2 || argc < 0) {
      Error2("%s: wrong number of parameters (%d instead of 0 or 1)",
	     argv[0], argc-1);
   }

   if (retropt_string(opts, OPT_TUN_DEVICE, &tundevice) != 0) {
      tundevice = strdup("/dev/net/tun");
   }

   /*! socket option here? */
   retropt_socket_pf(opts, &pf);

   namedargv[1] = tundevice;
   /* open the tun cloning device */
   if ((result = _xioopen_named_early(2, namedargv, xfd, groups, &exists, opts)) < 0) {
      return result;
   }

   /*========================= the tunnel interface =========================*/
   Notice("creating tunnel network interface");
   if ((result = _xioopen_open(tundevice, rw, opts)) < 0)
      return result;
   xfd->stream.fd = result;

   /* prepare configuration of the new network interface */
   memset(&ifr, 0,sizeof(ifr));

   if (retropt_string(opts, OPT_TUN_NAME, &tunname) == 0) {
      strncpy(ifr.ifr_name, tunname, IFNAMSIZ);	/* ok */
      free(tunname);
   } else {
      ifr.ifr_name[0] = '\0';
   }

   ifr.ifr_flags = IFF_TUN;
   if (retropt_string(opts, OPT_TUN_TYPE, &tuntype) == 0) {
      if (!strcmp(tuntype, "tap")) {
	 ifr.ifr_flags = IFF_TAP;
      } else if (strcmp(tuntype, "tun")) {
	 Error1("unknown tun-type \"%s\"", tuntype);
      }
   }

   if (retropt_bool(opts, OPT_IFF_NO_PI, &no_pi) == 0) {
      if (no_pi) {
	 ifr.ifr_flags |= IFF_NO_PI;
#if 0 /* not neccessary for now */
      } else {
	 ifr.ifr_flags &= ~IFF_NO_PI;
#endif
      }
   }

   if (Ioctl(xfd->stream.fd, TUNSETIFF, &ifr) < 0) {
      Error3("ioctl(%d, TUNSETIFF, {\"%s\"}: %s",
	     xfd->stream.fd, ifr.ifr_name, strerror(errno));
      Close(xfd->stream.fd);
   }

   /*===================== setting interface properties =====================*/

   /* we seem to need a socket for manipulating the interface */
   if ((sockfd = Socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
      Error1("socket(PF_INET, SOCK_DGRAM, 0): %s", strerror(errno));
      sockfd = xfd->stream.fd;	/* desparate fallback attempt */
   }

   /*--------------------- setting interface address and netmask ------------*/
   if (argc == 2) {
       if ((ifaddr = strdup(argv[1])) == NULL) {
          Error1("strdup(\"%s\"): out of memory", argv[1]);
          return STAT_RETRYLATER;
       }
       if ((result = xioparsenetwork(ifaddr, pf, &network)) != STAT_OK) {
          /*! recover */
          return result;
       }
       socket_init(pf, (union sockaddr_union *)&ifr.ifr_addr);
       ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr =
          network.netaddr.ip4.sin_addr;
       if (Ioctl(sockfd, SIOCSIFADDR, &ifr) < 0) {
          Error4("ioctl(%d, SIOCSIFADDR, {\"%s\", \"%s\"}: %s",
             sockfd, ifr.ifr_name, ifaddr, strerror(errno));
       }
       ((struct sockaddr_in *)&ifr.ifr_netmask)->sin_addr =
          network.netmask.ip4.sin_addr;
       if (Ioctl(sockfd, SIOCSIFNETMASK, &ifr) < 0) {
          Error4("ioctl(%d, SIOCSIFNETMASK, {\"0x%08u\", \"%s\"}, %s",
             sockfd, ((struct sockaddr_in *)&ifr.ifr_netmask)->sin_addr.s_addr,
             ifaddr, strerror(errno));
       }
       free(ifaddr);
   }
   /*--------------------- setting interface flags --------------------------*/
   applyopts_single(&xfd->stream, opts, PH_FD);

   if (Ioctl(sockfd, SIOCGIFFLAGS, &ifr) < 0) {
      Error3("ioctl(%d, SIOCGIFFLAGS, {\"%s\"}: %s",
	     sockfd, ifr.ifr_name, strerror(errno));
   }
   Debug2("\"%s\": system set flags: 0x%hx", ifr.ifr_name, ifr.ifr_flags);
   ifr.ifr_flags |= xfd->stream.para.tun.iff_opts[0];
   ifr.ifr_flags &= ~xfd->stream.para.tun.iff_opts[1];
   Debug2("\"%s\": xio merged flags: 0x%hx", ifr.ifr_name, ifr.ifr_flags);
   if (Ioctl(sockfd, SIOCSIFFLAGS, &ifr) < 0) {
      Error4("ioctl(%d, SIOCSIFFLAGS, {\"%s\", %hd}: %s",
	     sockfd, ifr.ifr_name, ifr.ifr_flags, strerror(errno));
   }
   ifr.ifr_flags = 0;
   if (Ioctl(sockfd, SIOCGIFFLAGS, &ifr) < 0) {
      Error3("ioctl(%d, SIOCGIFFLAGS, {\"%s\"}: %s",
	     sockfd, ifr.ifr_name, strerror(errno));
   }
   Debug2("\"%s\": resulting flags: 0x%hx", ifr.ifr_name, ifr.ifr_flags);


#if LATER
   applyopts_named(tundevice, opts, PH_FD);
#endif
   applyopts(xfd->stream.fd, opts, PH_FD);
   applyopts_cloexec(xfd->stream.fd, opts);

   applyopts_fchown(xfd->stream.fd, opts);

   if ((result = _xio_openlate(&xfd->stream, opts)) < 0)
      return result;

   return 0;
}
bool NPCType::Load(iResultRow &row)
{
    csString parents = row.GetString("parents");
    if(!parents.IsEmpty()) // this npctype is a subclass of another npctype
    {
        csArray<csString> parent = psSplit(parents,',');
        for(size_t i = 0; i < parent.GetSize(); i++)
        {
            NPCType *superclass = npcclient->FindNPCType(parent[i]);
            if(superclass)
            {
                DeepCopy(*superclass);  // This pulls everything from the parent into this one.
            }
            else
            {
                Error2("Specified parent npctype '%s' could not be found.",
                       parent[i].GetDataSafe());
                return false;
            }
        }
    }

    name = row.GetString("name");
    if(name.Length() == 0)
    {
        Error1("NPCType has no name attribute. Error in DB");
        return false;
    }

    ang_vel = row.GetFloat("ang_vel");

    csString velStr = row.GetString("vel");
    velStr.Upcase();

    if(velStr.IsEmpty())
    {
        // Do nothing. Use velSource from constructor default value
        // or as inherited from superclass.
    }
    else if(velStr == "$WALK")
    {
        velSource = VEL_WALK;
    }
    else if (velStr == "$RUN")
    {
        velSource = VEL_RUN;
    }
    else if(row.GetFloat("vel"))
    {
        velSource = VEL_USER;
        vel = row.GetFloat("vel");
    }

    collisionPerception   = row.GetString("collision");
    outOfBoundsPerception = row.GetString("out_of_ounds");
    inBoundsPerception    = row.GetString("in_bounds");
    fallingPerception     = row.GetString("falling");

    csRef<iDocumentSystem> xml = csPtr<iDocumentSystem>(new csTinyDocumentSystem);
    csRef<iDocument> doc = xml->CreateDocument();
    const char* error = doc->Parse(row.GetString("script"));
    if(error)
    {
        Error3("NPCType script parsing error:%s in %s", error, name.GetData());
        return false;
    }
    csRef<iDocumentNode> node = doc->GetRoot();
    if(!node)
    {
        Error2("No XML root in npc type script of %s", name.GetData());
        return false;
    }
    
    // Now read in behaviors and reactions
    csRef<iDocumentNodeIterator> iter = node->GetNodes();

    while(iter->HasNext())
    {
        csRef<iDocumentNode> node = iter->Next();
        if(node->GetType() != CS_NODE_ELEMENT)
            continue;

        // This is a widget so read it's factory to create it.
        if(strcmp(node->GetValue(), "behavior") == 0)
        {
            Behavior *b = new Behavior;
            if(!b->Load(node))
            {
                Error3("Could not load behavior '%s'. Error in DB XML in node '%s'.",
                       b->GetName(),node->GetValue());
                delete b;
                return false;
            }
            behaviors.Add(b);
            Debug3(LOG_STARTUP,0, "Added behavior '%s' to type %s.\n",b->GetName(),name.GetData() );
        }
        else if(strcmp( node->GetValue(), "react" ) == 0)
        {
            Reaction *r = new Reaction;
            if(!r->Load(node,behaviors))
            {
                Error1("Could not load reaction. Error in DB XML");
                delete r;
                return false;
            }
            // check for duplicates and keeps the last one
            for(size_t i=0; i<reactions.GetSize(); i++)
            {
                // Same event with same type
                if(!strcmp(reactions[i]->GetEventType(),r->GetEventType())&&
                    (reactions[i]->type == r->type)&&
                    (reactions[i]->values == r->values))
                {
                    // Check if there is a mach in affected
                    for(size_t k=0; k< r->affected.GetSize(); k++)
                    {
                        for(size_t j=0; j< reactions[i]->affected.GetSize(); j++)
                        {
                            if(!strcmp(r->affected[k]->GetName(),reactions[i]->affected[j]->GetName()))
                            {
                                // Should probably delete and clear out here
                                // to allow for overiding of event,affected pairs.
                                // Though now give error, until needed.
                                Error4("Reaction of type '%s' already connected to '%s' in '%s'",
                                       r->GetEventType(),reactions[i]->affected[j]->GetName(), name.GetDataSafe());
                                return false;
                                // delete reactions[i];
                                //reactions.DeleteIndex(i);
                                //break;
                            }
                        }
                    }
                }
            }

            reactions.Insert(0,r);  // reactions get inserted at beginning so subclass ones take precedence over superclass.
        }
        else
        {
            Error1("Node under NPCType is not 'behavior' or 'react'. Error in DB XML");
            return false;
        }
    }
    return true; // success
}
Beispiel #8
0
static int xioopen_exec(int argc, const char *argv[], struct opt *opts,
		int xioflags,	/* XIO_RDONLY, XIO_MAYCHILD etc. */
		xiofile_t *fd,
		unsigned groups,
		int dummy1, int dummy2, int dummy3
		) {
   int status;
   bool dash = false;
   int duptostderr;

   if (argc != 2) {
      Error3("\"%s:%s\": wrong number of parameters (%d instead of 1)", argv[0], argv[1], argc-1);
   }
      
   retropt_bool(opts, OPT_DASH, &dash);

   status = _xioopen_foxec(xioflags, &fd->stream, groups, &opts, &duptostderr);
   if (status < 0)  return status;
   if (status == 0) {	/* child */
      const char *ends[] = { " ", NULL };
      const char *hquotes[] = { "'", NULL };
      const char *squotes[] = { "\"", NULL };
      const char *nests[] = {
	 "'", "'",
	 "(", ")",
	 "[", "]",
	 "{", "}",
	 NULL
      } ;
      char **pargv = NULL;
      int pargc;
      size_t len;
      const char *strp;
      char *token; /*! */
      char *tokp;
      char *path = NULL;
      char *tmp;
      int numleft;

      /*! Close(something) */
      /* parse command line */
      Debug1("child: args = \"%s\"", argv[1]);
      pargv = Malloc(8*sizeof(char *));
      if (pargv == NULL)  return STAT_RETRYLATER;
      len = strlen(argv[1])+1;
      strp = argv[1];
      token = Malloc(len); /*! */
      tokp = token;
      if (nestlex(&strp, &tokp, &len, ends, hquotes, squotes, nests,
		  true, true, false) < 0) {
	 Error("internal: miscalculated string lengths");
      }
      *tokp++ = '\0';
      pargv[0] = strrchr(tokp-1, '/');
      if (pargv[0] == NULL)  pargv[0] = token;  else  ++pargv[0];
      pargc = 1;
      while (*strp == ' ') {
	 while (*++strp == ' ')  ;
	 if ((pargc & 0x07) == 0) {
	    pargv = Realloc(pargv, (pargc+8)*sizeof(char *));
	    if (pargv == NULL)  return STAT_RETRYLATER;
	 }
	 pargv[pargc++] = tokp;
	 if (nestlex(&strp, &tokp, &len, ends, hquotes, squotes, nests,
		     true, true, false) < 0) {
	    Error("internal: miscalculated string lengths");
	 }
	 *tokp++ = '\0';
      }
      pargv[pargc] = NULL;

      if ((tmp = Malloc(strlen(pargv[0])+2)) == NULL) {
	 return STAT_RETRYLATER;
      }
      if (dash) {
	 tmp[0] = '-';
	 strcpy(tmp+1, pargv[0]);
      } else {
	 strcpy(tmp, pargv[0]);
      }
      pargv[0] = tmp;

      if (setopt_path(opts, &path) < 0) {
	 /* this could be dangerous, so let us abort this child... */
	 Exit(1);
      }

      if ((numleft = leftopts(opts)) > 0) {
	 Error1("%d option(s) could not be used", numleft);
	 showleft(opts);
	 return STAT_NORETRY;
      }

      /* only now redirect stderr */
      if (duptostderr >= 0) {
	 diag_dup();
	 Dup2(duptostderr, 2);
      }
      Notice1("execvp'ing \"%s\"", token);
      Execvp(token, pargv);
      /* here we come only if execvp() failed */
      switch (pargc) {
      case 1: Error3("execvp(\"%s\", \"%s\"): %s", token, pargv[0], strerror(errno)); break; 
      case 2: Error4("execvp(\"%s\", \"%s\", \"%s\"): %s", token, pargv[0], pargv[1], strerror(errno)); break; 
      case 3:
      default:
	 Error5("execvp(\"%s\", \"%s\", \"%s\", \"%s\", ...): %s", token, pargv[0], pargv[1], pargv[2], strerror(errno)); break; 
      }
      Exit(1);	/* this child process */
   }

   /* parent */
   return 0;
}
Beispiel #9
0
static int xioopen_pty(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *xfd, unsigned groups, int dummy1, int dummy2, int dummy3) {
   /* we expect the form: filename */
   int ptyfd = -1, ttyfd = -1;
#if defined(HAVE_DEV_PTMX) || defined(HAVE_DEV_PTC)
   bool useptmx = false;	/* use /dev/ptmx or equivalent */
#endif
#if HAVE_OPENPTY
   bool useopenpty = false;	/* try only openpty */
#endif	/* HAVE_OPENPTY */
   char ptyname[MAXPTYNAMELEN];
   char *tn = NULL;
   char *linkname = NULL;
   bool opt_unlink_close = true;	/* remove symlink afterwards */
   bool wait_slave = false;	/* true would be better for many platforms, but
				   some OSes cannot handle this, and for common
				   default behaviour as well as backward 
				   compatibility we choose "no" as default */
   struct timespec pollintv = { PTY_INTERVALL };

   if (argc != 1) {
      Error2("%s: wrong number of parameters (%d instead of 0)", argv[0], argc-1);
   }

   xfd->stream.howtoend = END_CLOSE;

   if (applyopts_single(&xfd->stream, opts, PH_INIT) < 0)  return -1;
   applyopts(-1, opts, PH_INIT);

   retropt_bool(opts, OPT_UNLINK_CLOSE, &opt_unlink_close);

   /* trying to set user-early, perm-early etc. here might be useless because
      file system entry is eventually available only past pty creation */
   /* name not yet known; umask should not be handled with this function! */
   /* umask does not affect resulting mode, on Linux 2.4 */
   applyopts_named("", opts, PH_EARLY);	/* umask! */

#if defined(HAVE_DEV_PTMX) || defined(HAVE_DEV_PTC)
   retropt_bool(opts, OPT_PTMX, &useptmx);
#endif
#if HAVE_OPENPTY
   retropt_bool(opts, OPT_OPENPTY, &useopenpty);
#endif

#if (defined(HAVE_DEV_PTMX) || defined(HAVE_DEV_PTC))
#  if  HAVE_OPENPTY
   useopenpty = !useptmx;
#  else /* !HAVE_OPENPTY */
   useptmx = true;
#  endif /* !HAVE_OPENPTY */
#else
# if HAVE_OPENPTY
   useopenpty = true;
# endif /* HAVE_OPENPTY */
#endif /* ! (defined(HAVE_DEV_PTMX) || defined(HAVE_DEV_PTC)) */

#if HAVE_POLL
   retropt_bool(opts, OPT_PTY_WAIT_SLAVE, &wait_slave);
   retropt_timespec(opts, OPT_PTY_INTERVALL, &pollintv);
#endif /* HAVE_POLL */

   if (applyopts_single(&xfd->stream, opts, PH_INIT) < 0)  return -1;
   applyopts2(-1, opts, PH_INIT, PH_EARLY);

   applyopts(-1, opts, PH_PREBIGEN);

#if defined(HAVE_DEV_PTMX)
#  define PTMX "/dev/ptmx"	/* Linux */
#elif HAVE_DEV_PTC
#  define PTMX "/dev/ptc"	/* AIX 4.3.3 */
#endif
#if HAVE_DEV_PTMX || HAVE_DEV_PTC
   if (useptmx) {
      if ((ptyfd = Open(PTMX, O_RDWR|O_NOCTTY, 0620)) < 0) {
	 Warn1("open(\""PTMX"\", O_RDWR|O_NOCTTY, 0620): %s",
	       strerror(errno));
	 /*!*/
      } else {
	 ;/*0 Info1("open(\""PTMX"\", O_RDWR|O_NOCTTY, 0620) -> %d", ptyfd);*/
      }
      if (ptyfd >= 0 && ttyfd < 0) {
	 /* we used PTMX before forking */
	 /*0 extern char *ptsname(int);*/
#if HAVE_GRANTPT	/* AIX, not Linux */
	 if (Grantpt(ptyfd)/*!*/ < 0) {
	    Warn2("grantpt(%d): %s", ptyfd, strerror(errno));
	 }
#endif /* HAVE_GRANTPT */
#if HAVE_UNLOCKPT
	 if (Unlockpt(ptyfd)/*!*/ < 0) {
	    Warn2("unlockpt(%d): %s", ptyfd, strerror(errno));
	 }
#endif /* HAVE_UNLOCKPT */
#if HAVE_PROTOTYPE_LIB_ptsname	/* AIX, not Linux */
	 if ((tn = Ptsname(ptyfd)) == NULL) {
	    Warn2("ptsname(%d): %s", ptyfd, strerror(errno));
	 } else {
	    Notice1("PTY is %s", tn);
	 }
#endif /* HAVE_PROTOTYPE_LIB_ptsname */
	 if (tn == NULL) {
	    if ((tn = Ttyname(ptyfd)) == NULL) {
	       Warn2("ttyname(%d): %s", ptyfd, strerror(errno));
	    }
	 }
	 ptyname[0] = '\0'; strncat(ptyname, tn, MAXPTYNAMELEN-1);
      }
   }
#endif /* HAVE_DEV_PTMX || HAVE_DEV_PTC */
#if HAVE_OPENPTY
   if (ptyfd < 0) {
      int result;
      if ((result = Openpty(&ptyfd, &ttyfd, ptyname, NULL, NULL)) < 0) {
	 Error4("openpty(%p, %p, %p, NULL, NULL): %s",
		&ptyfd, &ttyfd, ptyname, strerror(errno));
	 return -1;
      }
      Notice1("PTY is %s", ptyname);
   }
#endif /* HAVE_OPENPTY */

   if (!retropt_string(opts, OPT_SYMBOLIC_LINK, &linkname)) {
      if (Unlink(linkname) < 0 && errno != ENOENT) {
	 Error2("unlink(\"%s\"): %s", linkname, strerror(errno));
      }
      if (Symlink(ptyname, linkname) < 0) {
	 Error3("symlink(\"%s\", \"%s\"): %s",
		ptyname, linkname, strerror(errno));
      }
      if (opt_unlink_close) {
	 if ((xfd->stream.unlink_close = strdup(linkname)) == NULL) {
	    Error1("strdup(\"%s\"): out of memory", linkname);
	 }
	 xfd->stream.opt_unlink_close = true;
      }
   }

   applyopts_named(ptyname, opts, PH_PASTOPEN);
   applyopts_named(ptyname, opts, PH_FD);

   applyopts_cloexec(ptyfd, opts);/*!*/
   xfd->stream.dtype    = XIODATA_PTY;

   applyopts(ptyfd, opts, PH_FD);

   {
      /* special handling of user-late etc.; with standard behaviour (up to
	 1.7.1.1) they affected /dev/ptmx instead of /dev/pts/N */
      uid_t uid = -1, gid = -1;
      mode_t perm;

      bool dont;
      dont = retropt_uid(opts, OPT_USER_LATE, &uid);
      dont &= retropt_gid(opts, OPT_GROUP_LATE, &gid);

      if (!dont) {
	 if (Chown(ptyname, uid, gid) < 0) {
	    Error4("chown(\"%s\", %d, %d): %s",
		   ptyname, uid, gid, strerror(errno));
	 }
      }

      if (retropt_mode(opts, OPT_PERM_LATE, &perm) == 0) {
	 if (Chmod(ptyname, perm) < 0) {
	    Error3("chmod(\"%s\", %03o): %s",
		   ptyname, perm, strerror(errno));
	 }
      }

   }

   xfd->stream.fd = ptyfd;
   applyopts(ptyfd, opts, PH_LATE);
   if (applyopts_single(&xfd->stream, opts, PH_LATE) < 0)  return -1;

#if HAVE_POLL
   /* if you can and wish: */
   if (wait_slave) {
      /* try to wait until someone opens the slave side of the pty */
      /* we want to get a HUP (hangup) condition on the pty */
#if HAVE_DEV_PTMX || HAVE_DEV_PTC
      if (useptmx) {
	 ttyfd = Open(tn, O_RDWR|O_NOCTTY, 0620);
	 Close(ttyfd);
      }
#endif
#if HAVE_OPENPTY
      if (useopenpty) {
	 Close(ttyfd);
      }
#endif /* HAVE_OPENPTY */

      /* now we poll until the HUP vanishes - this indicates a slave conn. */
      while (true) {
	 struct pollfd ufd;
	 ufd.fd = ptyfd;
	 ufd.events = (POLLHUP);
	 if (Poll(&ufd, 1, 0) < 0) {
	    Error3("poll({%d, 0x%04hu,}, 1, 0): %s",
		   ufd.fd, ufd.events, strerror(errno));
	    /*! close something */
	    return -1;
	 }
	 if (!(ufd.revents & POLLHUP)) {
	    break;
	 }
	 Nanosleep(&pollintv, NULL);
	 continue;
      }
   }
#endif /* HAVE_POLL */

   return STAT_OK;
}
Beispiel #10
0
void NetManager::CheckResendPkts()
{
    // NOTE: Globaliterators on csHash do not retrieve keys contiguously.
    csHash<csRef<psNetPacketEntry>, PacketKey>::GlobalIterator it (awaitingack.GetIterator());
    csRef<psNetPacketEntry> pkt;
    csArray<csRef<psNetPacketEntry> > pkts;
    csArray<Connection*> resentConnections;

    // Connections that should be avoided because we know they are full
    csArray<Connection*> fullConnections;

    csTicks currenttime = csGetTicks();
    unsigned int resentCount = 0;

    while(it.HasNext())
    {
        pkt = it.Next();
        // Check the connection packet timeout
        if (pkt->timestamp + MIN(PKTMAXRTO, pkt->RTO) < currenttime)
            pkts.Push(pkt);
    }
    for (size_t i = 0; i < pkts.GetSize(); i++)
    {
#ifdef PACKETDEBUG
        Debug2(LOG_NET,"Resending nonacked HIGH packet (ID %d).\n", pkt->packet->pktid);
#endif
        pkt = pkts.Get(i);

        // re-add to send queue
        csRef<NetPacketQueueRefCount> outqueue = clients.FindQueueAny(pkt->clientnum);
        if (!outqueue)
        {
            awaitingack.Delete(PacketKey(pkt->clientnum, pkt->packet->pktid), pkt);
            continue;
        }

        Connection* connection = GetConnByNum(pkt->clientnum);
        if (connection)
        {
            if (resentConnections.Find(connection) == csArrayItemNotFound)
                resentConnections.Push(connection);
            if (fullConnections.Find(connection) != csArrayItemNotFound)
                continue;
            // This indicates a bug in the netcode.
            if (pkt->RTO == 0)
            {
                Error1("Unexpected 0 packet RTO.");
                abort();
            }
            pkt->RTO *= 2;
            connection->resends++;
        }
        resentCount++;

        pkt->timestamp = currenttime;   // update stamp on packet
        pkt->retransmitted = true;

        /*  The proper way to send a message is to add it to the queue, and then add the queue to the senders.
        *  If you do it the other way around the net thread may remove the queue from the senders before you add the packet.
        *   Yes - this has actually happened!
        */

        /* We store the result here to return as the result of this function to maintain historic functionality.
        *  In actuality a false response does not actually mean no data was added to the queue, just that
        *  not all of the data could be added.
        */
        if (!outqueue->Add(pkt))
        {
            psNetPacket* packet = pkt->packet;
            int type = 0;

            if (packet->offset == 0)
            {
                psMessageBytes* msg = (psMessageBytes*) packet->data;
                type = msg->type;
            }
            Error4("Queue full. Could not add packet with clientnum %d type %s ID %d.\n", pkt->clientnum, type == 0 ? "Fragment" : (const char *)  GetMsgTypeName(type), pkt->packet->pktid);
            fullConnections.Push(connection);
            continue;
        }

        /**
        * The senders list is a list of busy queues.  The SendOut() function
        * in NetBase clears this list each time through.  This saves having
        * to check every single connection each time through.
        */

        if (!senders.Add (outqueue))
            Error1("Senderlist Full!");

        //printf("pkt=%p, pkt->packet=%p\n",pkt,pkt->packet);
        // take out of awaiting ack pool.
        // This does NOT delete the pkt mem block itself.
        if (!awaitingack.Delete(PacketKey(pkt->clientnum, pkt->packet->pktid), pkt))
        {
#ifdef PACKETDEBUG
            Debug2(LOG_NET,"No packet in ack queue :%d\n", pkt->packet->pktid);
#endif
        }
        else if(connection)
            connection->RemoveFromWindow(pkt->packet->GetPacketSize());
    }
    if(resentCount > 0)
    {
        resends[resendIndex] = resentCount;
        resendIndex = (resendIndex + 1) % RESENDAVGCOUNT;

        csTicks timeTaken = csGetTicks() - currenttime;
        if(resendIndex == 1 || timeTaken > 50)
        {
            unsigned int peakResend = 0;
            float resendAvg = 0.0f;
            // Calculate averages data here
            for(int i = 0; i < RESENDAVGCOUNT; i++)
            {
                resendAvg += resends[i];
                peakResend = MAX(peakResend, resends[i]);
            }
            resendAvg /= RESENDAVGCOUNT;
            csString status;
            if(timeTaken > 50 || pkts.GetSize() > 300)
            {
                status.Format("Resending high priority packets has taken %u time to process, for %u packets on %zu unique connections %zu full connections (Sample clientnum %u/RTO %u. ", timeTaken, resentCount, resentConnections.GetSize(),fullConnections.GetSize(), resentConnections[0]->clientnum, resentConnections[0]->RTO);
                CPrintf(CON_WARNING, "%s\n", (const char *) status.GetData());
            }
            status.AppendFmt("Resending non-acked packet statistics: %g average resends, peak of %u resent packets", resendAvg, peakResend);

            if(LogCSV::GetSingletonPtr())
                LogCSV::GetSingleton().Write(CSV_STATUS, status);
        }

    }

}