int main(void) { Error1(); Error2(); Error3(); Error4(); Error6(); printf("Pareciera que esta todo bien!!\n"); }
/* 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; }
/* 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; }
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()); } }
/* 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; }
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 }
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; }
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; }
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); } } }