/* * Create socket for incoming connections and bind to it an address for * clients to use. Returns -1 on failure. * * If '*family' is AF_UNIX and unix domain sockets are supported: * 'port' is ignored and 'address' is the path to the socket file in the filesystem. * * Otherwise: * address is a string representing the Inet/IPv6 address that the port * is advertised for. To allow connections to all this host's internet * addresses from clients use address == "INADDR_ANY", or for localhost * access only use address == "INADDR_LOOPBACK". * On input, 'family' is a pointer to the address family to use (AF_INET, * AF_INET6) if the address specified is empty. If the spec is not * empty then family is ignored and is set to the actual address family * used. 'family' must be initialized to AF_UNSPEC, in this case. */ static int OpenRequestSocket(int port, const char *address, int *family, int backlog, __pmFdSet *fdset, int *maximum) { int fd = -1; int one, sts; __pmSockAddr *myAddr; int isUnix = 0; /* * Using this flag will eliminate the need for more conditional * compilation below, hopefully making the code easier to read and maintain. */ #if defined(HAVE_STRUCT_SOCKADDR_UN) if (*family == AF_UNIX) isUnix = 1; #endif if (isUnix) { if ((myAddr = __pmSockAddrAlloc()) == NULL) { __pmNoMem("OpenRequestSocket: can't allocate socket address", sizeof(*myAddr), PM_FATAL_ERR); } /* Initialize the address. */ __pmSockAddrSetFamily(myAddr, *family); __pmSockAddrSetPath(myAddr, address); /* Create the socket. */ fd = __pmCreateUnixSocket(); } else { /* * If the address is unspecified, then use the address family we * have been given, otherwise the family will be determined by * __pmStringToSockAddr. */ if (address == NULL || strcmp(address, "INADDR_ANY") == 0) { if ((myAddr = __pmSockAddrAlloc()) == NULL) { __pmNoMem("OpenRequestSocket: can't allocate socket address", sizeof(*myAddr), PM_FATAL_ERR); } __pmSockAddrInit(myAddr, *family, INADDR_ANY, 0); } else if (strcmp(address, "INADDR_LOOPBACK") == 0) { if ((myAddr = __pmSockAddrAlloc()) == NULL) { __pmNoMem("OpenRequestSocket: can't allocate socket address", sizeof(*myAddr), PM_FATAL_ERR); } __pmSockAddrInit(myAddr, *family, INADDR_LOOPBACK, 0); } else { if ((myAddr = __pmStringToSockAddr(address)) == NULL) { __pmNotifyErr(LOG_ERR, "OpenRequestSocket(%d, %s) invalid address\n", port, address); goto fail; } *family = __pmSockAddrGetFamily(myAddr); } __pmSockAddrSetPort(myAddr, port); /* Create the socket. */ if (*family == AF_INET) fd = __pmCreateSocket(); else if (*family == AF_INET6) fd = __pmCreateIPv6Socket(); else { __pmNotifyErr(LOG_ERR, "OpenRequestSocket(%d, %s) invalid address family: %d\n", port, address, *family); goto fail; } } if (fd < 0) { __pmNotifyErr(LOG_ERR, "OpenRequestSocket(%d, %s, %s) __pmCreateSocket: %s\n", port, address, AddressFamily(*family), netstrerror()); goto fail; } /* Ignore dead client connections. */ one = 1; #ifndef IS_MINGW if (__pmSetSockOpt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&one, (__pmSockLen)sizeof(one)) < 0) { __pmNotifyErr(LOG_ERR, "OpenRequestSocket(%d, %s, %s) __pmSetSockOpt(SO_REUSEADDR): %s\n", port, address, AddressFamily(*family), netstrerror()); goto fail; } #else if (__pmSetSockOpt(fd, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (char *)&one, (__pmSockLen)sizeof(one)) < 0) { __pmNotifyErr(LOG_ERR, "OpenRequestSocket(%d, %s, %s) __pmSetSockOpt(EXCLUSIVEADDRUSE): %s\n", port, address, AddressFamily(*family), netstrerror()); goto fail; } #endif /* and keep alive please - bad networks eat fds */ if (__pmSetSockOpt(fd, SOL_SOCKET, SO_KEEPALIVE, (char *)&one, (__pmSockLen)sizeof(one)) < 0) { __pmNotifyErr(LOG_ERR, "OpenRequestSocket(%d, %s, %s) __pmSetSockOpt(SO_KEEPALIVE): %s\n", port, address, AddressFamily(*family), netstrerror()); goto fail; } sts = __pmBind(fd, (void *)myAddr, __pmSockAddrSize()); __pmSockAddrFree(myAddr); myAddr = NULL; if (sts < 0) { sts = neterror(); __pmNotifyErr(LOG_ERR, "OpenRequestSocket(%d, %s, %s) __pmBind: %s\n", port, address, AddressFamily(*family), netstrerror()); if (sts == EADDRINUSE) __pmNotifyErr(LOG_ERR, "%s may already be running\n", pmProgname); goto fail; } if (isUnix) { /* * For unix domain sockets, grant rw access to the socket for all, * otherwise, on linux platforms, connection will not be possible. * This must be done AFTER binding the address. See Unix(7) for details. */ sts = chmod(address, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH); if (sts != 0) { __pmNotifyErr(LOG_ERR, "OpenRequestSocket(%d, %s, %s) chmod(%s): %s\n", port, address, AddressFamily(*family), address, strerror(errno)); goto fail; } } sts = __pmListen(fd, backlog); /* Max. pending connection requests */ if (sts < 0) { __pmNotifyErr(LOG_ERR, "OpenRequestSocket(%d, %s, %s) __pmListen: %s\n", port, address, AddressFamily(*family), netstrerror()); goto fail; } if (fd > *maximum) *maximum = fd; __pmFD_SET(fd, fdset); return fd; fail: if (fd != -1) { __pmCloseSocket(fd); /* We must unlink the socket file. */ if (isUnix) unlink(address); } if (myAddr) __pmSockAddrFree(myAddr); return -1; }
/* * Reads the metadata of an HTTP response. * Perhaps a little inefficient, as it reads 1 byte at a time, but * I don't think it's that much of a loss (most headers aren't HUGE). * Returns: * # of bytes read on success, or * -1 on error */ int _http_read_header(int sock, char *headerPtr) { fd_set rfds; struct timeval tv; int bytesRead = 0, newlines = 0, ret, selectRet; while(newlines != 2 && bytesRead != HEADER_BUF_SIZE) { FD_ZERO(&rfds); FD_SET(sock, &rfds); tv.tv_sec = timeout; tv.tv_usec = 0; if(timeout >= 0) selectRet = select(sock+1, &rfds, NULL, NULL, &tv); else /* No timeout, can block indefinately */ selectRet = select(sock+1, &rfds, NULL, NULL, NULL); if(selectRet == 0) { errorSource = FETCHER_ERROR; http_errno = HF_HEADTIMEOUT; errorInt = timeout; return -1; } else if(selectRet == -1) { setoserror(neterror()); errorSource = ERRNO; return -1; } ret = recv(sock, headerPtr, 1, 0); if(ret == -1) { setoserror(neterror()); errorSource = ERRNO; return -1; } bytesRead++; if(*headerPtr == '\r') /* Ignore CR */ { /* Basically do nothing special, just don't set newlines * to 0 */ headerPtr++; continue; } else if(*headerPtr == '\n') /* LF is the separator */ newlines++; else newlines = 0; headerPtr++; } headerPtr -= 3; /* Snip the trailing LF's */ *headerPtr = '\0'; return bytesRead; }
static int negotiate_proxy(int fd, const char *hostname, int port) { char buf[MY_BUFLEN]; char *bp; int ok = 0; /* * version negotiation (converse to pmproxy logic) * __pmSend my client version message * __pmRecv server version message * __pmSend hostname and port */ if (__pmSend(fd, MY_VERSION, strlen(MY_VERSION), 0) != strlen(MY_VERSION)) { char errmsg[PM_MAXERRMSGLEN]; __pmNotifyErr(LOG_WARNING, "__pmConnectPMCD: send version string to pmproxy failed: %s\n", pmErrStr_r(-neterror(), errmsg, sizeof(errmsg))); return PM_ERR_IPC; } for (bp = buf; bp < &buf[MY_BUFLEN]; bp++) { if (__pmRecv(fd, bp, 1, 0) != 1) { *bp = '\0'; bp = &buf[MY_BUFLEN]; break; } if (*bp == '\n' || *bp == '\r') { *bp = '\0'; break; } } if (bp < &buf[MY_BUFLEN]) { if (strcmp(buf, "pmproxy-server 1") == 0) ok = 1; } if (!ok) { __pmNotifyErr(LOG_WARNING, "__pmConnectPMCD: bad version string from pmproxy: \"%s\"\n", buf); return PM_ERR_IPC; } snprintf(buf, sizeof(buf), "%s %d\n", hostname, port); if (__pmSend(fd, buf, strlen(buf), 0) != strlen(buf)) { char errmsg[PM_MAXERRMSGLEN]; __pmNotifyErr(LOG_WARNING, "__pmConnectPMCD: send hostname+port string to pmproxy failed: %s'\n", pmErrStr_r(-neterror(), errmsg, sizeof(errmsg))); return PM_ERR_IPC; } return ok; }
/* Loop, synchronously processing requests from clients. */ static void ClientLoop(void) { int i, sts; int maxFd; __pmFdSet readableFds; for (;;) { /* Figure out which file descriptors to wait for input on. Keep * track of the highest numbered descriptor for the select call. */ readableFds = sockFds; maxFd = maxSockFd + 1; sts = __pmSelectRead(maxFd, &readableFds, NULL); if (sts > 0) { if (pmDebug & DBG_TRACE_APPL0) for (i = 0; i <= maxSockFd; i++) if (__pmFD_ISSET(i, &readableFds)) fprintf(stderr, "__pmSelectRead(): from %s fd=%d\n", FdToString(i), i); __pmServerAddNewClients(&readableFds, CheckNewClient); HandleInput(&readableFds); } else if (sts == -1 && neterror() != EINTR) { __pmNotifyErr(LOG_ERR, "ClientLoop select: %s\n", netstrerror()); break; } if (timeToDie) { SignalShutdown(); break; } } }
/* Establish a new socket connection to a client */ ClientInfo * AcceptNewClient(int reqfd) { static unsigned int seq = 0; int i, fd; __pmSockLen addrlen; struct timeval now; i = NewClient(); addrlen = __pmSockAddrSize(); fd = __pmAccept(reqfd, client[i].addr, &addrlen); if (fd == -1) { if (neterror() == EPERM) { __pmNotifyErr(LOG_NOTICE, "AcceptNewClient(%d): " "Permission Denied\n", reqfd); client[i].fd = -1; DeleteClient(&client[i]); return NULL; } else { __pmNotifyErr(LOG_ERR, "AcceptNewClient(%d) __pmAccept: %s\n", reqfd, netstrerror()); Shutdown(); exit(1); } } if (fd > maxClientFd) maxClientFd = fd; pmcd_openfds_sethi(fd); __pmFD_SET(fd, &clientFds); __pmSetVersionIPC(fd, UNKNOWN_VERSION); /* before negotiation */ __pmSetSocketIPC(fd); client[i].fd = fd; client[i].status.connected = 1; client[i].status.changes = 0; memset(&client[i].attrs, 0, sizeof(__pmHashCtl)); /* * Note seq needs to be unique, but we're using a free running counter * and not bothering to check here ... unless we churn through * 4,294,967,296 (2^32) clients while one client remains connected * we won't have a problem */ client[i].seq = seq++; __pmtimevalNow(&now); client[i].start = now.tv_sec; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) fprintf(stderr, "AcceptNewClient(%d): client[%d] (fd %d)\n", reqfd, i, fd); #endif pmcd_trace(TR_ADD_CLIENT, i, 0, 0); return &client[i]; }
// // UDPsocket // SOCKET UDPsocket (void) { SOCKET s; // allocate a socket s = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP); if (s == INVALID_SOCKET) I_FatalError ("can't create socket: %s", neterror ()); return s; }
void BuildAddress (sockaddr_in *address, const char *name) { hostent *hostentry; // host information entry u_short port; const char *portpart; bool isnamed = false; int curchar; char c; FString target; address->sin_family = AF_INET; if ( (portpart = strchr (name, ':')) ) { target = FString(name, portpart - name); port = atoi (portpart + 1); if (!port) { Printf ("Weird port: %s (using %d)\n", portpart + 1, DOOMPORT); port = DOOMPORT; } } else { target = name; port = DOOMPORT; } address->sin_port = htons(port); for (curchar = 0; (c = target[curchar]) ; curchar++) { if ((c < '0' || c > '9') && c != '.') { isnamed = true; break; } } if (!isnamed) { address->sin_addr.s_addr = inet_addr (target); Printf ("Node number %d, address %s\n", doomcom.numnodes, target.GetChars()); } else { hostentry = gethostbyname (target); if (!hostentry) I_FatalError ("gethostbyname: couldn't find %s\n%s", target.GetChars(), neterror()); address->sin_addr.s_addr = *(int *)hostentry->h_addr_list[0]; Printf ("Node number %d, hostname %s\n", doomcom.numnodes, hostentry->h_name); } }
void loggerMain(pmdaInterface *dispatch) { fd_set readyfds; int nready, pmcdfd; pmcdfd = __pmdaInFd(dispatch); if (pmcdfd > maxfd) maxfd = pmcdfd; FD_ZERO(&fds); FD_SET(pmcdfd, &fds); /* arm interval timer */ if (__pmAFregister(&interval, NULL, logger_timer) < 0) { __pmNotifyErr(LOG_ERR, "registering event interval handler"); exit(1); } for (;;) { memcpy(&readyfds, &fds, sizeof(readyfds)); nready = select(maxfd+1, &readyfds, NULL, NULL, NULL); if (pmDebug & DBG_TRACE_APPL2) __pmNotifyErr(LOG_DEBUG, "select: nready=%d interval=%d", nready, interval_expired); if (nready < 0) { if (neterror() != EINTR) { __pmNotifyErr(LOG_ERR, "select failure: %s", netstrerror()); exit(1); } else if (!interval_expired) { continue; } } __pmAFblock(); if (nready > 0 && FD_ISSET(pmcdfd, &readyfds)) { if (pmDebug & DBG_TRACE_APPL0) __pmNotifyErr(LOG_DEBUG, "processing pmcd PDU [fd=%d]", pmcdfd); if (__pmdaMainPDU(dispatch) < 0) { __pmAFunblock(); exit(1); /* fatal if we lose pmcd */ } if (pmDebug & DBG_TRACE_APPL0) __pmNotifyErr(LOG_DEBUG, "completed pmcd PDU [fd=%d]", pmcdfd); } if (interval_expired) { interval_expired = 0; event_refresh(); } __pmAFunblock(); } }
// // BindToLocalPort // void BindToLocalPort (SOCKET s, u_short port) { int v; sockaddr_in address; memset (&address, 0, sizeof(address)); address.sin_family = AF_INET; address.sin_addr.s_addr = INADDR_ANY; address.sin_port = htons(port); v = bind (s, (sockaddr *)&address, sizeof(address)); if (v == SOCKET_ERROR) I_FatalError ("BindToPort: %s", neterror ()); }
sockaddr_in *PreGet (void *buffer, int bufferlen, bool noabort) { static sockaddr_in fromaddress; socklen_t fromlen; int c; fromlen = sizeof(fromaddress); c = recvfrom (mysocket, (char *)buffer, bufferlen, 0, (sockaddr *)&fromaddress, &fromlen); if (c == SOCKET_ERROR) { int err = WSAGetLastError(); if (err == WSAEWOULDBLOCK || (noabort && err == WSAECONNRESET)) return NULL; // no packet I_Error ("PreGet: %s", neterror ()); } return &fromaddress; }
void systemdMain(pmdaInterface *dispatch) { int pmcdfd; pmcdfd = __pmdaInFd(dispatch); if (pmcdfd > maxfd) maxfd = pmcdfd; FD_SET(pmcdfd, &fds); for (;;) { fd_set readyfds; int nready; struct timeval select_timeout = interval; memcpy(&readyfds, &fds, sizeof(readyfds)); nready = select(maxfd+1, &readyfds, NULL, NULL, & select_timeout); if (pmDebug & DBG_TRACE_APPL2) __pmNotifyErr(LOG_DEBUG, "select: nready=%d interval=%d", nready, interval_expired); if (nready < 0) { if (neterror() != EINTR) { __pmNotifyErr(LOG_ERR, "select failure: %s", netstrerror()); exit(1); } else if (!interval_expired) { continue; } } if (nready > 0 && FD_ISSET(pmcdfd, &readyfds)) { if (pmDebug & DBG_TRACE_APPL0) __pmNotifyErr(LOG_DEBUG, "processing pmcd PDU [fd=%d]", pmcdfd); if (__pmdaMainPDU(dispatch) < 0) { exit(1); /* fatal if we lose pmcd */ } if (pmDebug & DBG_TRACE_APPL0) __pmNotifyErr(LOG_DEBUG, "completed pmcd PDU [fd=%d]", pmcdfd); } systemd_refresh(); } }
static void server_resolve_success(int servidx) { int oldserv = dcc[servidx].u.dns->ibuf; char s[121], pass[121]; resolvserv = 0; dcc[servidx].addr = dcc[servidx].u.dns->ip; strcpy(pass, dcc[servidx].u.dns->cbuf); changeover_dcc(servidx, &SERVER_SOCKET, 0); serv = open_telnet(iptostr(htonl(dcc[servidx].addr)), dcc[servidx].port); if (serv < 0) { neterror(s); putlog(LOG_SERV, "*", "%s %s (%s)", IRC_FAILEDCONNECT, dcc[servidx].host, s); lostdcc(servidx); if (oldserv == curserv && !never_give_up) fatal("NO SERVERS WILL ACCEPT MY CONNECTION.", 0); } else { dcc[servidx].sock = serv; /* Queue standard login */ dcc[servidx].timeval = now; SERVER_SOCKET.timeout_val = &server_timeout; /* Another server may have truncated it, so use the original */ strcpy(botname, origbotname); /* Start alternate nicks from the beginning */ altnick_char = 0; if (pass[0]) dprintf(DP_MODE, "PASS %s\n", pass); dprintf(DP_MODE, "NICK %s\n", botname); rmspace(botrealname); if (botrealname[0] == 0) strcpy(botrealname, "/msg LamestBot hello"); dprintf(DP_MODE, "USER %s . . :%s\n", botuser, botrealname); /* Wait for async result now. */ } }
static int tcl_connect(ClientData cd, Tcl_Interp *irp, int argc, char *argv[]) { int i, z, sock; char s[81]; BADARGS(3, 3, " hostname port"); if (dcc_total == max_dcc) { Tcl_AppendResult(irp, "out of dcc table space", NULL); return TCL_ERROR; } sock = getsock(0); if (sock < 0) { Tcl_AppendResult(irp, MISC_NOFREESOCK, NULL); return TCL_ERROR; } z = open_telnet_raw(sock, argv[1], atoi(argv[2])); if (z < 0) { killsock(sock); if (z == -2) strncpyz(s, "DNS lookup failed", sizeof s); else neterror(s); Tcl_AppendResult(irp, s, NULL); return TCL_ERROR; } i = new_dcc(&DCC_SOCKET, 0); dcc[i].sock = sock; dcc[i].port = atoi(argv[2]); strcpy(dcc[i].nick, "*"); strncpyz(dcc[i].host, argv[1], UHOSTMAX); egg_snprintf(s, sizeof s, "%d", sock); Tcl_AppendResult(irp, s, NULL); return TCL_OK; }
// // PacketGet // void PacketGet (void) { int c; socklen_t fromlen; sockaddr_in fromaddress; int node; fromlen = sizeof(fromaddress); c = recvfrom (mysocket, (char*)TransmitBuffer, TRANSMIT_SIZE, 0, (sockaddr *)&fromaddress, &fromlen); node = FindNode (&fromaddress); if (node >= 0 && c == SOCKET_ERROR) { int err = WSAGetLastError(); if (err == WSAECONNRESET) { // The remote node aborted unexpectedly, so pretend it sent an exit packet if (StartScreen != NULL) { StartScreen->NetMessage ("The connection from %s was dropped.\n", players[sendplayer[node]].userinfo.GetName()); } else { Printf("The connection from %s was dropped.\n", players[sendplayer[node]].userinfo.GetName()); } doomcom.data[0] = 0x80; // NCMD_EXIT c = 1; } else if (err != WSAEWOULDBLOCK) { I_Error ("GetPacket: %s", neterror ()); } else { doomcom.remotenode = -1; // no packet return; } } else if (c > 0) { doomcom.data[0] = TransmitBuffer[0] & ~NCMD_COMPRESSED; if (TransmitBuffer[0] & NCMD_COMPRESSED) { uLongf msgsize = MAX_MSGLEN - 1; int err = uncompress(doomcom.data + 1, &msgsize, TransmitBuffer + 1, c - 1); // Printf("recv %d/%lu\n", c, msgsize + 1); if (err != Z_OK) { Printf("Net decompression failed (zlib error %s)\n", M_ZLibError(err).GetChars()); // Pretend no packet doomcom.remotenode = -1; return; } c = msgsize + 1; } else { // Printf("recv %d\n", c); memcpy(doomcom.data + 1, TransmitBuffer + 1, c - 1); } } doomcom.remotenode = node; doomcom.datalength = (short)c; }
static int _pmauxtraceconnect(void) { int port = TRACE_PORT; char hostname[MAXHOSTNAMELEN]; struct timeval timeout = { 3, 0 }; /* default 3 secs */ __pmSockAddr *myaddr; __pmHostEnt *servinfo; void *enumIx; #ifndef IS_MINGW struct itimerval _pmolditimer; void (*old_handler)(int foo); #endif int rc, sts; int flags = 0; char *sptr, *endptr, *endnum; struct timeval canwait = { 5, 000000 }; struct timeval stv; struct timeval *pstv; __pmFdSet wfds; #ifdef PMTRACE_DEBUG if (__pmstate & PMTRACE_STATE_NOAGENT) { fprintf(stderr, "_pmtraceconnect: connecting to PMDA (skipped)\n"); return 0; } else if (__pmstate & PMTRACE_STATE_COMMS) fprintf(stderr, "_pmtraceconnect: connecting to PMDA ...\n"); #endif /* * get optional stuff from environment ... * PCP_TRACE_HOST, PCP_TRACE_PORT, PCP_TRACE_TIMEOUT, and * PCP_TRACE_NOAGENT */ if ((sptr = getenv(TRACE_ENV_HOST)) != NULL) strcpy(hostname, sptr); else { (void)gethostname(hostname, MAXHOSTNAMELEN); hostname[MAXHOSTNAMELEN-1] = '\0'; } if ((sptr = getenv(TRACE_ENV_PORT)) != NULL) { port = (int)strtol(sptr, &endnum, 0); if (*endnum != '\0' || port < 0) { fprintf(stderr, "trace warning: bad PCP_TRACE_PORT ignored."); port = TRACE_PORT; } } if ((sptr = getenv(TRACE_ENV_TIMEOUT)) != NULL) { double timesec = strtod(sptr, &endptr); if (*endptr != '\0' || timesec < 0.0) fprintf(stderr, "trace warning: bogus PCP_TRACE_TIMEOUT."); else { timeout.tv_sec = (time_t)timesec; timeout.tv_usec = (int)((timesec - (double)timeout.tv_sec)*1000000); } } if (getenv(TRACE_ENV_NOAGENT) != NULL) __pmstate |= PMTRACE_STATE_NOAGENT; if ((servinfo = __pmGetAddrInfo(hostname)) == NULL) { #ifdef PMTRACE_DEBUG if (__pmstate & PMTRACE_STATE_COMMS) fprintf(stderr, "_pmtraceconnect(__pmGetAddrInfo(hostname=%s): " "hosterror=%d, ``%s''\n", hostname, hosterror(), hoststrerror()); #endif return -EHOSTUNREACH; } /* Try each address in turn until one connects. */ sts = EHOSTUNREACH; __pmfd = -1; enumIx = NULL; for (myaddr = __pmHostEntGetSockAddr(servinfo, &enumIx); myaddr != NULL; myaddr = __pmHostEntGetSockAddr(servinfo, &enumIx)) { /* Create a socket */ if (__pmSockAddrIsInet(myaddr)) __pmfd = __pmCreateSocket(); else if (__pmSockAddrIsIPv6(myaddr)) __pmfd = __pmCreateIPv6Socket(); else { fprintf(stderr, "_pmtraceconnect(invalid address family): %d\n", __pmSockAddrGetFamily(myaddr)); } if (__pmfd < 0) { sts = neterror(); __pmSockAddrFree(myaddr); continue; /* Try the next address */ } /* Set the port. */ __pmSockAddrSetPort(myaddr, port); #ifndef IS_MINGW /* arm interval timer */ _pmmyitimer.it_value.tv_sec = timeout.tv_sec; _pmmyitimer.it_value.tv_usec = timeout.tv_usec; _pmmyitimer.it_interval.tv_sec = 0; _pmmyitimer.it_interval.tv_usec = 0; old_handler = signal(SIGALRM, _pmtracealarm); setitimer(ITIMER_REAL, &_pmmyitimer, &_pmolditimer); #endif #ifdef PMTRACE_DEBUG if (__pmstate & PMTRACE_STATE_COMMS) { char *name = __pmHostEntGetName (servinfo); fprintf(stderr, "_pmtraceconnect: PMDA host=%s port=%d timeout=%d" "secs\n", name == NULL ? "unknown" : name, port, (int)timeout.tv_sec); if (name != NULL) free(name); } #endif /* Attempt to connect */ flags = __pmConnectTo(__pmfd, myaddr, port); __pmSockAddrFree(myaddr); if (flags < 0) { /* * Mark failure in case we fall out the end of the loop * and try next address. __pmfd has been closed in __pmConnectTo(). */ sts = -flags; __pmfd = -1; continue; } /* FNDELAY and we're in progress - wait on select */ stv = canwait; pstv = (stv.tv_sec || stv.tv_usec) ? &stv : NULL; __pmFD_ZERO(&wfds); __pmFD_SET(__pmfd, &wfds); if ((rc = __pmSelectWrite(__pmfd+1, &wfds, pstv)) == 1) { sts = __pmConnectCheckError(__pmfd); } else if (rc == 0) { sts = ETIMEDOUT; } else { sts = (rc < 0) ? neterror() : EINVAL; } #ifndef IS_MINGW /* re-arm interval timer */ setitimer(ITIMER_REAL, &off_itimer, &_pmmyitimer); signal(SIGALRM, old_handler); if (_pmolditimer.it_value.tv_sec != 0 && _pmolditimer.it_value.tv_usec != 0) { _pmolditimer.it_value.tv_usec -= timeout.tv_usec - _pmmyitimer.it_value.tv_usec; while (_pmolditimer.it_value.tv_usec < 0) { _pmolditimer.it_value.tv_usec += 1000000; _pmolditimer.it_value.tv_sec--; } while (_pmolditimer.it_value.tv_usec > 1000000) { _pmolditimer.it_value.tv_usec -= 1000000; _pmolditimer.it_value.tv_sec++; } _pmolditimer.it_value.tv_sec -= timeout.tv_sec - _pmmyitimer.it_value.tv_sec; if (_pmolditimer.it_value.tv_sec < 0) { /* missed the user's itimer, pretend there is 1 msec to go! */ _pmolditimer.it_value.tv_sec = 0; _pmolditimer.it_value.tv_usec = 1000; } setitimer(ITIMER_REAL, &_pmolditimer, &_pmmyitimer); } #endif /* Was the connection successful? */ if (sts == 0) break; /* Unsuccessful connection. */ __pmCloseSocket(__pmfd); __pmfd = -1; } /* loop over addresses */ __pmHostEntFree(servinfo); /* Was the connection successful? */ if (__pmfd < 0) { #ifdef PMTRACE_DEBUG if (__pmstate & PMTRACE_STATE_COMMS) fprintf(stderr, "_pmtraceconnect(socket failed): %s\n", netstrerror()); #endif return -sts; } _pmtimedout = 0; /* Restore the original file status flags. */ if (__pmSetFileStatusFlags(__pmfd, flags) < 0) { #ifdef PMTRACE_DEBUG if (__pmstate & PMTRACE_STATE_COMMS) fprintf(stderr, ":_pmtraceconnect: cannot restore file status flags\n"); #endif return -oserror(); } /* make sure this file descriptor is closed if exec() is called */ if ((flags = __pmGetFileDescriptorFlags(__pmfd)) != -1) sts = __pmSetFileDescriptorFlags(__pmfd, flags | FD_CLOEXEC); else sts = -1; if (sts == -1) return -oserror(); if (__pmtraceprotocol(TRACE_PROTOCOL_QUERY) == TRACE_PROTOCOL_ASYNC) { /* in the asynchronoous protocol - ensure no delay after close */ if ((flags = __pmGetFileStatusFlags(__pmfd)) != -1) sts = __pmSetFileStatusFlags(__pmfd, flags | FNDELAY); else sts = -1; if (sts == -1) return -oserror(); #ifdef PMTRACE_DEBUG if (__pmstate & PMTRACE_STATE_COMMS) fprintf(stderr, "_pmtraceconnect: async protocol setup complete\n"); #endif } else #ifdef PMTRACE_DEBUG if (__pmstate & PMTRACE_STATE_COMMS) fprintf(stderr, "_pmtraceconnect: sync protocol setup complete\n"); #endif /* trace PMDA sends an ACK on successful connect */ sts = _pmtracegetack(sts, 0); return sts; }
/* * Actually downloads the page, registering a hit (donation) * If the fileBuf passed in is NULL, the url is downloaded and then * freed; otherwise the necessary space is allocated for fileBuf. * Returns size of download on success, -1 on error is set, */ int http_fetch(const char *url_tmp, char **fileBuf) { fd_set rfds; struct timeval tv; char headerBuf[HEADER_BUF_SIZE]; char *tmp, *url, *pageBuf, *requestBuf = NULL, *host, *charIndex; int sock, bytesRead = 0, contentLength = -1, bufsize = REQUEST_BUF_SIZE; int i, ret = -1, tempSize, selectRet, found = 0, /* For redirects */ redirectsFollowed = 0; if(url_tmp == NULL) { errorSource = FETCHER_ERROR; http_errno = HF_NULLURL; return -1; } /* Copy the url passed in into a buffer we can work with, change, etc. */ url = malloc(strlen(url_tmp)+1); if(url == NULL) { errorSource = ERRNO; return -1; } strncpy(url, url_tmp, strlen(url_tmp) + 1); /* This loop allows us to follow redirects if need be. An afterthought, * added to provide this basic functionality. Will hopefully be designed * better in 2.x.x ;) */ /* while(!found && (followRedirects < 0 || redirectsFollowed < followRedirects) ) */ do { /* Seek to the file path portion of the url */ charIndex = strstr(url, "://"); if(charIndex != NULL) { /* url contains a protocol field */ charIndex += strlen("://"); host = charIndex; charIndex = strchr(charIndex, '/'); } else { host = (char *)url; charIndex = strchr(url, '/'); } /* Compose a request string */ requestBuf = malloc(bufsize); if(requestBuf == NULL) { free(url); errorSource = ERRNO; return -1; } requestBuf[0] = 0; if(charIndex == NULL) { /* The url has no '/' in it, assume the user is making a root-level * request */ tempSize = strlen("GET /") + strlen(HTTP_VERSION) + 2; if(_checkBufSize(&requestBuf, &bufsize, tempSize) || snprintf(requestBuf, bufsize, "GET / %s\r\n", HTTP_VERSION) < 0) { free(url); free(requestBuf); errorSource = ERRNO; return -1; } } else { tempSize = strlen("GET ") + strlen(charIndex) + strlen(HTTP_VERSION) + 4; /* + 4 is for ' ', '\r', '\n', and NULL */ if(_checkBufSize(&requestBuf, &bufsize, tempSize) || snprintf(requestBuf, bufsize, "GET %s %s\r\n", charIndex, HTTP_VERSION) < 0) { free(url); free(requestBuf); errorSource = ERRNO; return -1; } } /* Null out the end of the hostname if need be */ if(charIndex != NULL) *charIndex = 0; /* Use Host: even though 1.0 doesn't specify it. Some servers * won't play nice if we don't send Host, and it shouldn't * hurt anything */ ret = bufsize - strlen(requestBuf); /* Space left in buffer */ tempSize = (int)strlen("Host: ") + (int)strlen(host) + 3; /* +3 for "\r\n\0" */ if(_checkBufSize(&requestBuf, &bufsize, tempSize + 128)) { free(url); free(requestBuf); errorSource = ERRNO; return -1; } strcat(requestBuf, "Host: "); strcat(requestBuf, host); strcat(requestBuf, "\r\n"); if(!hideReferer && referer != NULL) /* NO default referer */ { tempSize = (int)strlen("Referer: ") + (int)strlen(referer) + 3; /* + 3 is for '\r', '\n', and NULL */ if(_checkBufSize(&requestBuf, &bufsize, tempSize)) { free(url); free(requestBuf); errorSource = ERRNO; return -1; } strcat(requestBuf, "Referer: "); strcat(requestBuf, referer); strcat(requestBuf, "\r\n"); } if(!hideUserAgent && userAgent == NULL) { tempSize = (int)strlen("User-Agent: ") + (int)strlen(DEFAULT_USER_AGENT) + (int)strlen(VERSION) + 4; /* + 4 is for '\', '\r', '\n', and NULL */ if(_checkBufSize(&requestBuf, &bufsize, tempSize)) { free(url); free(requestBuf); errorSource = ERRNO; return -1; } strcat(requestBuf, "User-Agent: "); strcat(requestBuf, DEFAULT_USER_AGENT); strcat(requestBuf, "/"); strcat(requestBuf, VERSION); strcat(requestBuf, "\r\n"); } else if(!hideUserAgent) { tempSize = (int)strlen("User-Agent: ") + (int)strlen(userAgent) + 3; /* + 3 is for '\r', '\n', and NULL */ if(_checkBufSize(&requestBuf, &bufsize, tempSize)) { free(url); free(requestBuf); errorSource = ERRNO; return -1; } strcat(requestBuf, "User-Agent: "); strcat(requestBuf, userAgent); strcat(requestBuf, "\r\n"); } tempSize = (int)strlen("Connection: Close\r\n\r\n"); if(_checkBufSize(&requestBuf, &bufsize, tempSize)) { free(url); free(requestBuf); errorSource = ERRNO; return -1; } strcat(requestBuf, "Connection: Close\r\n\r\n"); /* Now free any excess memory allocated to the buffer */ tmp = realloc(requestBuf, strlen(requestBuf) + 1); if(tmp == NULL) { free(url); free(requestBuf); errorSource = ERRNO; return -1; } requestBuf = tmp; sock = makeSocket(host); /* errorSource set within makeSocket */ if(sock == -1) { free(url); free(requestBuf); return -1;} free(url); url = NULL; if(write(sock, requestBuf, strlen(requestBuf)) == -1) { close(sock); free(requestBuf); errorSource = ERRNO; return -1; } free(requestBuf); requestBuf = NULL; /* Grab enough of the response to get the metadata */ ret = _http_read_header(sock, headerBuf); /* errorSource set within */ if(ret < 0) { close(sock); return -1; } /* Get the return code */ charIndex = strstr(headerBuf, "HTTP/"); if(charIndex == NULL) { close(sock); errorSource = FETCHER_ERROR; http_errno = HF_FRETURNCODE; return -1; } while(*charIndex != ' ') charIndex++; charIndex++; ret = sscanf(charIndex, "%d", &i); if(ret != 1) { close(sock); errorSource = FETCHER_ERROR; http_errno = HF_CRETURNCODE; return -1; } if(i<200 || i>307) { close(sock); errorInt = i; /* Status code, to be inserted in error string */ errorSource = FETCHER_ERROR; http_errno = HF_STATUSCODE; return -1; } /* If a redirect, repeat operation until final URL is found or we * redirect followRedirects times. Note the case sensitive "Location", * should probably be made more robust in the future (without relying * on the non-standard strcasecmp()). * This bit mostly by Dean Wilder, tweaked by me */ if(i >= 300) { redirectsFollowed++; /* Pick up redirect URL, allocate new url, and repeat process */ charIndex = strstr(headerBuf, "Location:"); if(!charIndex) { close(sock); errorInt = i; /* Status code, to be inserted in error string */ errorSource = FETCHER_ERROR; http_errno = HF_CANTREDIRECT; return -1; } charIndex += strlen("Location:"); /* Skip any whitespace... */ while(*charIndex != '\0' && isspace((int)*charIndex)) charIndex++; if(*charIndex == '\0') { close(sock); errorInt = i; /* Status code, to be inserted in error string */ errorSource = FETCHER_ERROR; http_errno = HF_CANTREDIRECT; return -1; } i = strcspn(charIndex, " \r\n"); if(i > 0) { url = (char *)malloc(i + 1); strncpy(url, charIndex, i); url[i] = '\0'; } else /* Found 'Location:' but contains no URL! We'll handle it as * 'found', hopefully the resulting document will give the user * a hint as to what happened. */ found = 1; } else found = 1; } while(!found && (followRedirects < 0 || redirectsFollowed <= followRedirects) ); if(url) /* Redirection code may malloc this, then exceed followRedirects */ { free(url); url = NULL; } if(redirectsFollowed >= followRedirects && !found) { close(sock); errorInt = followRedirects; /* To be inserted in error string */ errorSource = FETCHER_ERROR; http_errno = HF_MAXREDIRECTS; return -1; } /* * Parse out about how big the data segment is. * Note that under current HTTP standards (1.1 and prior), the * Content-Length field is not guaranteed to be accurate or even present. * I just use it here so I can allocate a ballpark amount of memory. * * Note that some servers use different capitalization */ charIndex = strstr(headerBuf, "Content-Length:"); if(charIndex == NULL) charIndex = strstr(headerBuf, "Content-length:"); if(charIndex != NULL) { ret = sscanf(charIndex + strlen("content-length: "), "%d", &contentLength); if(ret < 1) { close(sock); errorSource = FETCHER_ERROR; http_errno = HF_CONTENTLEN; return -1; } } /* Allocate enough memory to hold the page */ if(contentLength == -1) contentLength = DEFAULT_PAGE_BUF_SIZE; pageBuf = (char *)malloc(contentLength); if(pageBuf == NULL) { close(sock); errorSource = ERRNO; return -1; } /* Begin reading the body of the file */ while(ret > 0) { FD_ZERO(&rfds); FD_SET(sock, &rfds); tv.tv_sec = timeout; tv.tv_usec = 0; if(timeout >= 0) selectRet = select(sock+1, &rfds, NULL, NULL, &tv); else /* No timeout, can block indefinately */ selectRet = select(sock+1, &rfds, NULL, NULL, NULL); if(selectRet == 0) { errorSource = FETCHER_ERROR; http_errno = HF_DATATIMEOUT; errorInt = timeout; close(sock); free(pageBuf); return -1; } else if(selectRet == -1) { setoserror(neterror()); close(sock); free(pageBuf); errorSource = ERRNO; return -1; } ret = recv(sock, pageBuf + bytesRead, contentLength, 0); if(ret == -1) { setoserror(neterror()); close(sock); free(pageBuf); errorSource = ERRNO; return -1; } bytesRead += ret; if(ret > 0) { /* To be tolerant of inaccurate Content-Length fields, we'll * allocate another read-sized chunk to make sure we have * enough room. */ tmp = (char *)realloc(pageBuf, bytesRead + contentLength); if(tmp == NULL) { close(sock); free(pageBuf); errorSource = ERRNO; return -1; } pageBuf = tmp; } } /* * The download buffer is too large. Trim off the safety padding. * Note that we add one NULL byte to the end of the data, as it may not * already be NULL terminated and we can't be sure what type of data it * is or what the caller will do with it. */ tmp = (char *)realloc(pageBuf, bytesRead + 1); /* tmp shouldn't be null, since we're _shrinking_ the buffer, * and if it DID fail, we could go on with the too-large buffer, * but something would DEFINATELY be wrong, so we'll just give * an error message */ if(tmp == NULL) { close(sock); free(pageBuf); errorSource = ERRNO; return -1; } pageBuf = tmp; pageBuf[bytesRead] = '\0'; /* NULL terminate the data */ if(fileBuf == NULL) /* They just wanted us to "hit" the url */ free(pageBuf); else *fileBuf = pageBuf; close(sock); return bytesRead; }
static int http_client_connectunix(const char *path, struct timeval *timeout) { #if defined(HAVE_STRUCT_SOCKADDR_UN) __pmFdSet wfds; __pmSockAddr *myAddr; struct timeval stv, *ptv; int fdFlags = 0; int fd = -1; int sts; int rc; /* Initialize the socket address. */ if ((myAddr = __pmSockAddrAlloc()) == NULL) { if (pmDebug & DBG_TRACE_HTTP) fprintf(stderr, "HTTP connect unix(%s): out of memory\n", path); return -ENOMEM; } __pmSockAddrSetFamily(myAddr, AF_UNIX); __pmSockAddrSetPath(myAddr, path); if ((fd = __pmCreateUnixSocket()) < 0) { if (pmDebug & DBG_TRACE_HTTP) { char errmsg[PM_MAXERRMSGLEN]; fprintf(stderr, "HTTP connect unix(%s) unable to create socket: %s\n", path, osstrerror_r(errmsg, sizeof(errmsg))); } __pmSockAddrFree(myAddr); return fd; } /* Attempt to connect */ fdFlags = __pmConnectTo(fd, myAddr, -1); __pmSockAddrFree(myAddr); if (fdFlags < 0) { __pmCloseSocket(fd); return -ECONNREFUSED; } /* FNDELAY and we're in progress - wait on select */ stv = *timeout; ptv = (stv.tv_sec || stv.tv_usec) ? &stv : NULL; __pmFD_ZERO(&wfds); __pmFD_SET(fd, &wfds); sts = 0; if ((rc = __pmSelectWrite(fd+1, &wfds, ptv)) == 1) sts = __pmConnectCheckError(fd); else if (rc == 0) sts = ETIMEDOUT; else sts = (rc < 0) ? neterror() : EINVAL; if (sts != 0) { /* Unsuccessful connection. */ if (sts == ENOENT) sts = ECONNREFUSED; __pmCloseSocket(fd); fd = -sts; } if (fd < 0) return fd; /* * If we're here, it means we have a valid connection; restore the * flags and make sure this file descriptor is closed if exec() is * called */ return __pmConnectRestoreFlags(fd, fdFlags); #else if (pmDebug & DBG_TRACE_HTTP) __pmNotifyErr(LOG_ERR, "HTTP connect unix(%s) not supported\n", path); return -EOPNOTSUPP; #endif }
int main(int argc, char **argv) { int c; int sts; int sep = __pmPathSeparator(); int use_localtime = 0; int isdaemon = 0; char *pmnsfile = PM_NS_DEFAULT; char *username; char *logfile = "pmlogger.log"; /* default log (not archive) file name */ char *endnum; int i; task_t *tp; optcost_t ocp; __pmFdSet readyfds; char *p; char *runtime = NULL; int ctx; /* handle corresponding to ctxp below */ __pmContext *ctxp; /* pmlogger has just this one context */ int niter; pid_t target_pid = 0; __pmGetUsername(&username); /* * Warning: * If any of the pmlogger options change, make sure the * corresponding changes are made to pmnewlog when pmlogger * options are passed through from the control file */ while ((c = pmgetopt_r(argc, argv, &opts)) != EOF) { switch (c) { case 'c': /* config file */ if (access(opts.optarg, F_OK) == 0) configfile = opts.optarg; else { /* does not exist as given, try the standard place */ char *sysconf = pmGetConfig("PCP_VAR_DIR"); int sz = strlen(sysconf)+strlen("/config/pmlogger/")+strlen(opts.optarg)+1; if ((configfile = (char *)malloc(sz)) == NULL) __pmNoMem("config file name", sz, PM_FATAL_ERR); snprintf(configfile, sz, "%s%c" "config%c" "pmlogger%c" "%s", sysconf, sep, sep, sep, opts.optarg); if (access(configfile, F_OK) != 0) { /* still no good, error handling happens below */ free(configfile); configfile = opts.optarg; } } break; case 'D': /* debug flag */ sts = __pmParseDebug(opts.optarg); if (sts < 0) { pmprintf("%s: unrecognized debug flag specification (%s)\n", pmProgname, opts.optarg); opts.errors++; } else pmDebug |= sts; break; case 'h': /* hostname for PMCD to contact */ pmcd_host_conn = opts.optarg; break; case 'l': /* log file name */ logfile = opts.optarg; break; case 'L': /* linger if not primary logger */ linger = 1; break; case 'm': /* note for port map file */ note = opts.optarg; isdaemon = ((strcmp(note, "pmlogger_check") == 0) || (strcmp(note, "pmlogger_daily") == 0)); break; case 'n': /* alternative name space file */ pmnsfile = opts.optarg; break; case 'p': target_pid = (int)strtol(opts.optarg, &endnum, 10); if (*endnum != '\0') { pmprintf("%s: invalid process identifier (%s)\n", pmProgname, opts.optarg); opts.errors++; } else if (!__pmProcessExists(target_pid)) { pmprintf("%s: PID error - no such process (%d)\n", pmProgname, target_pid); opts.errors++; } break; case 'P': /* this is the primary pmlogger */ primary = 1; isdaemon = 1; break; case 'r': /* report sizes of pmResult records */ rflag = 1; break; case 's': /* exit size */ sts = ParseSize(opts.optarg, &exit_samples, &exit_bytes, &exit_time); if (sts < 0) { pmprintf("%s: illegal size argument '%s' for exit size\n", pmProgname, opts.optarg); opts.errors++; } else if (exit_time.tv_sec > 0) { __pmAFregister(&exit_time, NULL, run_done_callback); } break; case 'T': /* end time */ runtime = opts.optarg; break; case 't': /* change default logging interval */ if (pmParseInterval(opts.optarg, &delta, &p) < 0) { pmprintf("%s: illegal -t argument\n%s", pmProgname, p); free(p); opts.errors++; } break; case 'U': /* run as named user */ username = opts.optarg; isdaemon = 1; break; case 'u': /* flush output buffers after each fetch */ /* * all archive write I/O is unbuffered now, so maintain -u * for backwards compatibility only */ break; case 'v': /* volume switch after given size */ sts = ParseSize(opts.optarg, &vol_switch_samples, &vol_switch_bytes, &vol_switch_time); if (sts < 0) { pmprintf("%s: illegal size argument '%s' for volume size\n", pmProgname, opts.optarg); opts.errors++; } else if (vol_switch_time.tv_sec > 0) { vol_switch_afid = __pmAFregister(&vol_switch_time, NULL, vol_switch_callback); } break; case 'V': archive_version = (int)strtol(opts.optarg, &endnum, 10); if (*endnum != '\0' || archive_version != PM_LOG_VERS02) { pmprintf("%s: -V requires a version number of %d\n", pmProgname, PM_LOG_VERS02); opts.errors++; } break; case 'x': /* recording session control fd */ rsc_fd = (int)strtol(opts.optarg, &endnum, 10); if (*endnum != '\0' || rsc_fd < 0) { pmprintf("%s: -x requires a non-negative numeric argument\n", pmProgname); opts.errors++; } else { time(&rsc_start); } break; case 'y': use_localtime = 1; break; case '?': default: opts.errors++; break; } } if (primary && pmcd_host != NULL) { pmprintf( "%s: -P and -h are mutually exclusive; use -P only when running\n" "%s on the same (local) host as the PMCD to which it connects.\n", pmProgname, pmProgname); opts.errors++; } if (!opts.errors && opts.optind != argc - 1) { pmprintf("%s: insufficient arguments\n", pmProgname); opts.errors++; } if (opts.errors) { pmUsageMessage(&opts); exit(1); } if (rsc_fd != -1 && note == NULL) { /* add default note to indicate running with -x */ static char xnote[10]; snprintf(xnote, sizeof(xnote), "-x %d", rsc_fd); note = xnote; } /* if we are running as a daemon, change user early */ if (isdaemon) __pmSetProcessIdentity(username); __pmOpenLog("pmlogger", logfile, stderr, &sts); if (sts != 1) { fprintf(stderr, "%s: Warning: log file (%s) creation failed\n", pmProgname, logfile); /* continue on ... writing to stderr */ } /* base name for archive is here ... */ archBase = argv[opts.optind]; if (pmcd_host_conn == NULL) pmcd_host_conn = "local:"; /* initialise access control */ if (__pmAccAddOp(PM_OP_LOG_ADV) < 0 || __pmAccAddOp(PM_OP_LOG_MAND) < 0 || __pmAccAddOp(PM_OP_LOG_ENQ) < 0) { fprintf(stderr, "%s: access control initialisation failed\n", pmProgname); exit(1); } if (pmnsfile != PM_NS_DEFAULT) { if ((sts = pmLoadASCIINameSpace(pmnsfile, 1)) < 0) { fprintf(stderr, "%s: Cannot load namespace from \"%s\": %s\n", pmProgname, pmnsfile, pmErrStr(sts)); exit(1); } } if ((ctx = pmNewContext(PM_CONTEXT_HOST, pmcd_host_conn)) < 0) { fprintf(stderr, "%s: Cannot connect to PMCD on host \"%s\": %s\n", pmProgname, pmcd_host_conn, pmErrStr(ctx)); exit(1); } pmcd_host = (char *)pmGetContextHostName(ctx); if (strlen(pmcd_host) == 0) { fprintf(stderr, "%s: pmGetContextHostName(%d) failed\n", pmProgname, ctx); exit(1); } if (rsc_fd == -1) { /* no -x, so register client id with pmcd */ __pmSetClientIdArgv(argc, argv); } /* * discover fd for comms channel to PMCD ... */ if ((ctxp = __pmHandleToPtr(ctx)) == NULL) { fprintf(stderr, "%s: botch: __pmHandleToPtr(%d) returns NULL!\n", pmProgname, ctx); exit(1); } pmcdfd = ctxp->c_pmcd->pc_fd; PM_UNLOCK(ctxp->c_lock); if (configfile != NULL) { if ((yyin = fopen(configfile, "r")) == NULL) { fprintf(stderr, "%s: Cannot open config file \"%s\": %s\n", pmProgname, configfile, osstrerror()); exit(1); } } else { /* **ANY** Lex would read from stdin automagically */ configfile = "<stdin>"; } __pmOptFetchGetParams(&ocp); ocp.c_scope = 1; __pmOptFetchPutParams(&ocp); /* prevent early timer events ... */ __pmAFblock(); if (yyparse() != 0) exit(1); if (configfile != NULL) fclose(yyin); yyend(); #ifdef PCP_DEBUG fprintf(stderr, "Config parsed\n"); #endif fprintf(stderr, "Starting %slogger for host \"%s\" via \"%s\"\n", primary ? "primary " : "", pmcd_host, pmcd_host_conn); #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_LOG) { fprintf(stderr, "optFetch Cost Parameters: pmid=%d indom=%d fetch=%d scope=%d\n", ocp.c_pmid, ocp.c_indom, ocp.c_fetch, ocp.c_scope); fprintf(stderr, "\nAfter loading config ...\n"); for (tp = tasklist; tp != NULL; tp = tp->t_next) { if (tp->t_numvalid == 0) continue; fprintf(stderr, " state: %sin log, %savail, %s, %s", PMLC_GET_INLOG(tp->t_state) ? "" : "not ", PMLC_GET_AVAIL(tp->t_state) ? "" : "un", PMLC_GET_MAND(tp->t_state) ? "mand" : "adv", PMLC_GET_ON(tp->t_state) ? "on" : "off"); fprintf(stderr, " delta: %ld usec", (long)1000 * tp->t_delta.tv_sec + tp->t_delta.tv_usec); fprintf(stderr, " numpmid: %d\n", tp->t_numpmid); for (i = 0; i < tp->t_numpmid; i++) { fprintf(stderr, " %s (%s):\n", pmIDStr(tp->t_pmidlist[i]), tp->t_namelist[i]); } __pmOptFetchDump(stderr, tp->t_fetch); } } #endif if (!primary && tasklist == NULL && !linger) { fprintf(stderr, "Nothing to log, and not the primary logger instance ... good-bye\n"); exit(1); } if ((sts = __pmLogCreate(pmcd_host, archBase, archive_version, &logctl)) < 0) { fprintf(stderr, "__pmLogCreate: %s\n", pmErrStr(sts)); exit(1); } else { /* * try and establish $TZ from the remote PMCD ... * Note the label record has been set up, but not written yet */ char *name = "pmcd.timezone"; pmID pmid; pmResult *resp; __pmtimevalNow(&epoch); sts = pmUseContext(ctx); if (sts >= 0) sts = pmLookupName(1, &name, &pmid); if (sts >= 0) sts = pmFetch(1, &pmid, &resp); if (sts >= 0) { if (resp->vset[0]->numval > 0) { /* pmcd.timezone present */ strcpy(logctl.l_label.ill_tz, resp->vset[0]->vlist[0].value.pval->vbuf); /* prefer to use remote time to avoid clock drift problems */ epoch = resp->timestamp; /* struct assignment */ if (! use_localtime) pmNewZone(logctl.l_label.ill_tz); } #ifdef PCP_DEBUG else if (pmDebug & DBG_TRACE_LOG) { fprintf(stderr, "main: Could not get timezone from host %s\n", pmcd_host); } #endif pmFreeResult(resp); } } /* do ParseTimeWindow stuff for -T */ if (runtime) { struct timeval res_end; /* time window end */ struct timeval start; struct timeval end; struct timeval last_delta; char *err_msg; /* parsing error message */ time_t now; struct timeval now_tv; time(&now); now_tv.tv_sec = now; now_tv.tv_usec = 0; start = now_tv; end.tv_sec = INT_MAX; end.tv_usec = INT_MAX; sts = __pmParseTime(runtime, &start, &end, &res_end, &err_msg); if (sts < 0) { fprintf(stderr, "%s: illegal -T argument\n%s", pmProgname, err_msg); exit(1); } last_delta = res_end; tsub(&last_delta, &now_tv); __pmAFregister(&last_delta, NULL, run_done_callback); last_stamp = res_end; } fprintf(stderr, "Archive basename: %s\n", archBase); #ifndef IS_MINGW /* detach yourself from the launching process */ if (isdaemon) setpgid(getpid(), 0); #endif /* set up control port */ init_ports(); __pmFD_ZERO(&fds); for (i = 0; i < CFD_NUM; ++i) { if (ctlfds[i] >= 0) __pmFD_SET(ctlfds[i], &fds); } #ifndef IS_MINGW __pmFD_SET(pmcdfd, &fds); #endif if (rsc_fd != -1) __pmFD_SET(rsc_fd, &fds); numfds = maxfd() + 1; if ((sts = do_preamble()) < 0) fprintf(stderr, "Warning: problem writing archive preamble: %s\n", pmErrStr(sts)); sts = 0; /* default exit status */ parse_done = 1; /* enable callback processing */ __pmAFunblock(); for ( ; ; ) { int nready; #ifdef PCP_DEBUG if ((pmDebug & DBG_TRACE_APPL2) && (pmDebug & DBG_TRACE_DESPERATE)) { fprintf(stderr, "before __pmSelectRead(%d,...): run_done_alarm=%d vol_switch_alarm=%d log_alarm=%d\n", numfds, run_done_alarm, vol_switch_alarm, log_alarm); } #endif niter = 0; while (log_alarm && niter++ < 10) { __pmAFblock(); log_alarm = 0; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL2) fprintf(stderr, "delayed callback: log_alarm\n"); #endif for (tp = tasklist; tp != NULL; tp = tp->t_next) { if (tp->t_alarm) { tp->t_alarm = 0; do_work(tp); } } __pmAFunblock(); } if (vol_switch_alarm) { __pmAFblock(); vol_switch_alarm = 0; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL2) fprintf(stderr, "delayed callback: vol_switch_alarm\n"); #endif newvolume(VOL_SW_TIME); __pmAFunblock(); } if (run_done_alarm) { #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL2) fprintf(stderr, "delayed callback: run_done_alarm\n"); #endif run_done(0, NULL); /*NOTREACHED*/ } __pmFD_COPY(&readyfds, &fds); nready = __pmSelectRead(numfds, &readyfds, NULL); #ifdef PCP_DEBUG if ((pmDebug & DBG_TRACE_APPL2) && (pmDebug & DBG_TRACE_DESPERATE)) { fprintf(stderr, "__pmSelectRead(%d,...) done: nready=%d run_done_alarm=%d vol_switch_alarm=%d log_alarm=%d\n", numfds, nready, run_done_alarm, vol_switch_alarm, log_alarm); } #endif __pmAFblock(); if (nready > 0) { /* handle request on control port */ for (i = 0; i < CFD_NUM; ++i) { if (ctlfds[i] >= 0 && __pmFD_ISSET(ctlfds[i], &readyfds)) { if (control_req(ctlfds[i])) { /* new client has connected */ __pmFD_SET(clientfd, &fds); if (clientfd >= numfds) numfds = clientfd + 1; } } } if (clientfd >= 0 && __pmFD_ISSET(clientfd, &readyfds)) { /* process request from client, save clientfd in case client * closes connection, resetting clientfd to -1 */ int fd = clientfd; if (client_req()) { /* client closed connection */ __pmFD_CLR(fd, &fds); __pmCloseSocket(clientfd); clientfd = -1; numfds = maxfd() + 1; qa_case = 0; } } #ifndef IS_MINGW if (pmcdfd >= 0 && __pmFD_ISSET(pmcdfd, &readyfds)) { /* * do not expect this, given synchronous commumication with the * pmcd ... either pmcd has terminated, or bogus PDU ... or its * Win32 and we are operating under the different conditions of * our AF.c implementation there, which has to deal with a lack * of signal support on Windows - race condition exists between * this check and the async event timer callback. */ __pmPDU *pb; __pmPDUHdr *php; sts = __pmGetPDU(pmcdfd, ANY_SIZE, TIMEOUT_NEVER, &pb); if (sts <= 0) { if (sts < 0) fprintf(stderr, "Error: __pmGetPDU: %s\n", pmErrStr(sts)); disconnect(sts); } else { php = (__pmPDUHdr *)pb; fprintf(stderr, "Error: Unsolicited %s PDU from PMCD\n", __pmPDUTypeStr(php->type)); disconnect(PM_ERR_IPC); } if (sts > 0) __pmUnpinPDUBuf(pb); } #endif if (rsc_fd >= 0 && __pmFD_ISSET(rsc_fd, &readyfds)) { /* * some action on the recording session control fd * end-of-file means launcher has quit, otherwise we * expect one of these commands * V<number>\n - version * F<folio>\n - folio name * P<name>\n - launcher's name * R\n - launcher can replay * D\n - detach from launcher * Q\n - quit pmlogger */ char rsc_buf[MAXPATHLEN]; char *rp = rsc_buf; char myc; int fake_x = 0; for (rp = rsc_buf; ; rp++) { if (read(rsc_fd, &myc, 1) <= 0) { #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL2) fprintf(stderr, "recording session control: eof\n"); #endif if (rp != rsc_buf) { *rp = '\0'; fprintf(stderr, "Error: incomplete recording session control message: \"%s\"\n", rsc_buf); } fake_x = 1; break; } if (rp >= &rsc_buf[MAXPATHLEN]) { fprintf(stderr, "Error: absurd recording session control message: \"%100.100s ...\"\n", rsc_buf); fake_x = 1; break; } if (myc == '\n') { *rp = '\0'; break; } *rp = myc; } #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL2) { if (fake_x == 0) fprintf(stderr, "recording session control: \"%s\"\n", rsc_buf); } #endif if (fake_x) do_dialog('X'); else if (strcmp(rsc_buf, "Q") == 0 || strcmp(rsc_buf, "D") == 0 || strcmp(rsc_buf, "?") == 0) do_dialog(rsc_buf[0]); else if (rsc_buf[0] == 'F') folio_name = strdup(&rsc_buf[1]); else if (rsc_buf[0] == 'P') rsc_prog = strdup(&rsc_buf[1]); else if (strcmp(rsc_buf, "R") == 0) rsc_replay = 1; else if (rsc_buf[0] == 'V' && rsc_buf[1] == '0') { /* * version 0 of the recording session control ... * this is all we grok at the moment */ ; } else { fprintf(stderr, "Error: illegal recording session control message: \"%s\"\n", rsc_buf); do_dialog('X'); } } } else if (vol_switch_flag) { newvolume(VOL_SW_SIGHUP); vol_switch_flag = 0; } else if (nready < 0 && neterror() != EINTR) fprintf(stderr, "Error: select: %s\n", netstrerror()); __pmAFunblock(); if (target_pid && !__pmProcessExists(target_pid)) exit(EXIT_SUCCESS); if (exit_code) break; } exit(exit_code); }
sendrep(int rpfd, int rep_type, ...) { va_list args; char func[16]; char *msg; int n; char *p; char prtbuf[PRTBUFSZ]; char *q; char *rbp; int rc; char repbuf[REPBUFSZ+12]; int repsize; strcpy (func, "sendrep"); rbp = repbuf; marshall_LONG (rbp, CNS_MAGIC2); va_start (args, rep_type); marshall_LONG (rbp, rep_type); switch (rep_type) { case MSG_ERR: msg = va_arg (args, char *); vsprintf (prtbuf, msg, args); marshall_LONG (rbp, strlen (prtbuf) + 1); marshall_STRING (rbp, prtbuf); nslogit (func, "%s", prtbuf); break; case MSG_DATA: case MSG_LINKS: case MSG_REPLIC: case MSG_REPLICP: case MSG_REPLICX: case MSG_REPLICS: case MSG_GROUPS: case MSG_STATUSES: case MSG_FILEST: case MSG_GRPINFO: case MSG_USRINFO: n = va_arg (args, int); marshall_LONG (rbp, n); msg = va_arg (args, char *); memcpy (rbp, msg, n); /* marshalling already done */ rbp += n; break; case CNS_IRC: case CNS_RC: rc = va_arg (args, int); marshall_LONG (rbp, rc); break; } va_end (args); repsize = rbp - repbuf; if (netwrite (rpfd, repbuf, repsize) != repsize) { nslogit (func, NS002, "send", neterror()); if (rep_type == CNS_RC) netclose (rpfd); return (-1); } if (rep_type == CNS_RC) netclose (rpfd); return (0); }
int __pmXmitPDU(int fd, __pmPDU *pdubuf) { int socketipc = __pmSocketIPC(fd); int off = 0; int len; __pmPDUHdr *php = (__pmPDUHdr *)pdubuf; __pmIgnoreSignalPIPE(); #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_PDU) { int j; char *p; int jend = PM_PDU_SIZE(php->len); char strbuf[20]; /* clear the padding bytes, lest they contain garbage */ p = (char *)pdubuf + php->len; while (p < (char *)pdubuf + jend*sizeof(__pmPDU)) *p++ = '~'; /* buffer end */ if (mypid == -1) mypid = (int)getpid(); fprintf(stderr, "[%d]pmXmitPDU: %s fd=%d len=%d", mypid, __pmPDUTypeStr_r(php->type, strbuf, sizeof(strbuf)), fd, php->len); for (j = 0; j < jend; j++) { if ((j % 8) == 0) fprintf(stderr, "\n%03d: ", j); fprintf(stderr, "%8x ", pdubuf[j]); } putc('\n', stderr); } #endif len = php->len; php->len = htonl(php->len); php->from = htonl(php->from); php->type = htonl(php->type); while (off < len) { char *p = (char *)pdubuf; int n; p += off; n = socketipc ? __pmSend(fd, p, len-off, 0) : write(fd, p, len-off); if (n < 0) break; off += n; } php->len = ntohl(php->len); php->from = ntohl(php->from); php->type = ntohl(php->type); if (off != len) { if (socketipc) { if (__pmSocketClosed()) return PM_ERR_IPC; return neterror() ? -neterror() : PM_ERR_IPC; } return oserror() ? -oserror() : PM_ERR_IPC; } __pmOverrideLastFd(fd); if (php->type >= PDU_START && php->type <= PDU_FINISH) __pmPDUCntOut[php->type-PDU_START]++; return off; }
int DoFetch(ClientInfo *cip, __pmPDU* pb) { int i, j; int sts; int ctxnum; __pmTimeval when; int nPmids; pmID *pmidList; static pmResult *endResult = NULL; static int maxnpmids = 0; /* sizes endResult */ DomPmidList *dList; /* NOTE: NOT indexed by agent index */ static int nDoms = 0; static pmResult **results = NULL; static int *resIndex = NULL; __pmFdSet waitFds; __pmFdSet readyFds; int nWait; int maxFd; struct timeval timeout; if (nAgents > nDoms) { if (results != NULL) free(results); if (resIndex != NULL) free(resIndex); results = (pmResult **)malloc((nAgents + 1) * sizeof (pmResult *)); resIndex = (int *)malloc((nAgents + 1) * sizeof(int)); if (results == NULL || resIndex == NULL) { __pmNoMem("DoFetch.results", (nAgents + 1) * sizeof (pmResult *) + (nAgents + 1) * sizeof(int), PM_FATAL_ERR); } nDoms = nAgents; } memset(results, 0, (nAgents + 1) * sizeof(results[0])); sts = __pmDecodeFetch(pb, &ctxnum, &when, &nPmids, &pmidList); if (sts < 0) return sts; /* Check that a profile has been received from the specified context */ if (ctxnum < 0 || ctxnum >= cip->szProfile || cip->profile[ctxnum] == NULL) { __pmUnpinPDUBuf(pb); if (ctxnum < 0 || ctxnum >= cip->szProfile) __pmNotifyErr(LOG_ERR, "DoFetch: bad ctxnum=%d\n", ctxnum); else __pmNotifyErr(LOG_ERR, "DoFetch: no profile for ctxnum=%d\n", ctxnum); return PM_ERR_NOPROFILE; } if (nPmids > maxnpmids) { int need; if (endResult != NULL) free(endResult); need = (int)sizeof(pmResult) + (nPmids - 1) * (int)sizeof(pmValueSet *); if ((endResult = (pmResult *)malloc(need)) == NULL) { __pmNoMem("DoFetch.endResult", need, PM_FATAL_ERR); } maxnpmids = nPmids; } dList = SplitPmidList(nPmids, pmidList); /* For each domain in the split pmidList, dispatch the per-domain subset * of pmIDs to the appropriate agent. For DSO agents, the pmResult will * come back immediately. If a request cannot be sent to an agent, a * suitable pmResult (containing metric not available values) will be * returned. */ __pmFD_ZERO(&waitFds); nWait = 0; maxFd = -1; for (i = 0; dList[i].domain != -1; i++) { j = mapdom[dList[i].domain]; results[j] = SendFetch(&dList[i], &agent[j], cip, ctxnum); if (results[j] == NULL) { /* Wait for agent's response */ int fd = agent[j].outFd; agent[j].status.busy = 1; __pmFD_SET(fd, &waitFds); if (fd > maxFd) maxFd = fd; nWait++; } } /* Construct pmResult for bad-pmID list */ if (dList[i].listSize != 0) results[nAgents] = MakeBadResult(dList[i].listSize, dList[i].list, PM_ERR_NOAGENT); /* Wait for results to roll in from agents */ while (nWait > 0) { __pmFD_COPY(&readyFds, &waitFds); if (nWait > 1) { timeout.tv_sec = _pmcd_timeout; timeout.tv_usec = 0; retry: setoserror(0); sts = __pmSelectRead(maxFd+1, &readyFds, &timeout); if (sts == 0) { __pmNotifyErr(LOG_INFO, "DoFetch: select timeout"); /* Timeout, terminate agents with undelivered results */ for (i = 0; i < nAgents; i++) { if (agent[i].status.busy) { /* Find entry in dList for this agent */ for (j = 0; dList[j].domain != -1; j++) if (dList[j].domain == agent[i].pmDomainId) break; results[i] = MakeBadResult(dList[j].listSize, dList[j].list, PM_ERR_NOAGENT); pmcd_trace(TR_RECV_TIMEOUT, agent[i].outFd, PDU_RESULT, 0); CleanupAgent(&agent[i], AT_COMM, agent[i].inFd); } } break; } else if (sts < 0) { if (neterror() == EINTR) goto retry; /* this is not expected to happen! */ __pmNotifyErr(LOG_ERR, "DoFetch: fatal select failure: %s\n", netstrerror()); Shutdown(); exit(1); } } /* Read results from agents that have them ready */ for (i = 0; i < nAgents; i++) { AgentInfo *ap = &agent[i]; int pinpdu; if (!ap->status.busy || !__pmFD_ISSET(ap->outFd, &readyFds)) continue; ap->status.busy = 0; __pmFD_CLR(ap->outFd, &waitFds); nWait--; pinpdu = sts = __pmGetPDU(ap->outFd, ANY_SIZE, _pmcd_timeout, &pb); if (sts > 0) pmcd_trace(TR_RECV_PDU, ap->outFd, sts, (int)((__psint_t)pb & 0xffffffff)); if (sts == PDU_RESULT) { if ((sts = __pmDecodeResult(pb, &results[i])) >= 0) if (results[i]->numpmid != aFreq[i]) { pmFreeResult(results[i]); sts = PM_ERR_IPC; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) __pmNotifyErr(LOG_ERR, "DoFetch: \"%s\" agent given %d pmIDs, returned %d\n", ap->pmDomainLabel, aFreq[i], results[i]->numpmid); #endif } } else { if (sts == PDU_ERROR) { int s; if ((s = __pmDecodeError(pb, &sts)) < 0) sts = s; else if (sts >= 0) sts = PM_ERR_GENERIC; pmcd_trace(TR_RECV_ERR, ap->outFd, PDU_RESULT, sts); } else if (sts >= 0) { pmcd_trace(TR_WRONG_PDU, ap->outFd, PDU_RESULT, sts); sts = PM_ERR_IPC; } } if (pinpdu > 0) __pmUnpinPDUBuf(pb); if (sts < 0) { /* Find entry in dList for this agent */ for (j = 0; dList[j].domain != -1; j++) if (dList[j].domain == agent[i].pmDomainId) break; results[i] = MakeBadResult(dList[j].listSize, dList[j].list, sts); if (sts == PM_ERR_PMDANOTREADY) { /* the agent is indicating it can't handle PDUs for now */ int k; extern int CheckError(AgentInfo *ap, int sts); for (k = 0; k < dList[j].listSize; k++) results[i]->vset[k]->numval = PM_ERR_AGAIN; sts = CheckError(&agent[i], sts); } #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) { fprintf(stderr, "RESULT error from \"%s\" agent : %s\n", ap->pmDomainLabel, pmErrStr(sts)); } #endif if (sts == PM_ERR_IPC || sts == PM_ERR_TIMEOUT) CleanupAgent(ap, AT_COMM, ap->outFd); } } } endResult->numpmid = nPmids; __pmtimevalNow(&endResult->timestamp); /* The order of the pmIDs in the per-domain results is the same as in the * original request, but on a per-domain basis. resIndex is an array of * indices (one per agent) of the next metric to be retrieved from each * per-domain result's vset. */ memset(resIndex, 0, (nAgents + 1) * sizeof(resIndex[0])); for (i = 0; i < nPmids; i++) { j = mapdom[((__pmID_int *)&pmidList[i])->domain]; endResult->vset[i] = results[j]->vset[resIndex[j]++]; } pmcd_trace(TR_XMIT_PDU, cip->fd, PDU_RESULT, endResult->numpmid); sts = 0; if (cip->status.changes) { /* notify client of PMCD state change */ sts = __pmSendError(cip->fd, FROM_ANON, (int)cip->status.changes); if (sts > 0) sts = 0; cip->status.changes = 0; } if (sts == 0) sts = __pmSendResult(cip->fd, FROM_ANON, endResult); if (sts < 0) { pmcd_trace(TR_XMIT_ERR, cip->fd, PDU_RESULT, sts); CleanupClient(cip, sts); } /* * pmFreeResult() all the accumulated results. */ for (i = 0; dList[i].domain != -1; i++) { j = mapdom[dList[i].domain]; if (agent[j].ipcType == AGENT_DSO && agent[j].status.connected && !agent[j].status.madeDsoResult) /* Living DSO's manage their own pmResult skeleton unless * MakeBadResult was called to create the result. The value sets * within the skeleton need to be freed though! */ __pmFreeResultValues(results[j]); else /* For others it is dynamically allocated in __pmDecodeResult or * MakeBadResult */ pmFreeResult(results[j]); } if (results[nAgents] != NULL) pmFreeResult(results[nAgents]); __pmUnpinPDUBuf(pmidList); return 0; }
/* this only handles CHAT requests, otherwise it's handled in filesys */ static int filesys_DCC_CHAT(char *nick, char *from, char *handle, char *object, char *keyword, char *text) { char *param, *ip, *prt, buf[512], *msg = buf; int i, sock; struct userrec *u = get_user_by_handle(userlist, handle); struct flag_record fr = {FR_GLOBAL | FR_CHAN | FR_ANYWH, 0, 0, 0, 0, 0}; Context; if (!strncasecmp(text, "SEND ", 5)) { filesys_dcc_send(nick, from, u, text + 5); return 1; } if (strncasecmp(text, "CHAT ", 5) || !u) return 0; strcpy(buf, text + 5); get_user_flagrec(u, &fr, 0); param = newsplit(&msg); if (dcc_total == max_dcc) { putlog(LOG_MISC, "*", DCC_TOOMANYDCCS2, "CHAT(file)", param, nick, from); } else if (glob_party(fr) || (!require_p && chan_op(fr))) return 0; /* allow ctcp.so to pick up the chat */ else if (!glob_xfer(fr)) { if (!quiet_reject) dprintf(DP_HELP, "NOTICE %s :.\n", nick, DCC_REFUSED3); putlog(LOG_MISC, "*", "%s: %s!%s", DCC_REFUSED, nick, from); } else if (u_pass_match(u, "-")) { if (!quiet_reject) dprintf(DP_HELP, "NOTICE %s :%s.\n", nick, DCC_REFUSED3); putlog(LOG_MISC, "*", "%s: %s!%s", DCC_REFUSED4, nick, from); } else if (!dccdir[0]) { putlog(LOG_MISC, "*", "%s: %s!%s", DCC_REFUSED5, nick, from); } else { ip = newsplit(&msg); prt = newsplit(&msg); sock = getsock(0); if (open_telnet_dcc(sock, ip, prt) < 0) { neterror(buf); if (!quiet_reject) dprintf(DP_HELP, "NOTICE %s :%s (%s)\n", nick, DCC_CONNECTFAILED1, buf); putlog(LOG_MISC, "*", "%s: CHAT(file) (%s!%s)", DCC_CONNECTFAILED2, nick, from); putlog(LOG_MISC, "*", " (%s)", buf); killsock(sock); } else if ((atoi(prt) < min_dcc_port) || (atoi(prt) > max_dcc_port)) { /* invalid port range, do clients even use over 5000?? */ if (!quiet_reject) dprintf(DP_HELP, "NOTICE %s :%s (invalid port)\n", nick, DCC_CONNECTFAILED1); putlog(LOG_FILES, "*", "%s: %s!%s", DCC_REFUSED7, nick, from); } else { i = new_dcc(&DCC_FILES_PASS, sizeof(struct file_info)); dcc[i].addr = my_atoul(ip); dcc[i].port = atoi(prt); dcc[i].sock = sock; strcpy(dcc[i].nick, u->handle); strcpy(dcc[i].host, from); dcc[i].status = STAT_ECHO; dcc[i].timeval = now; dcc[i].u.file->chat = get_data_ptr(sizeof(struct chat_info)); bzero(dcc[i].u.file->chat, sizeof(struct chat_info)); strcpy(dcc[i].u.file->chat->con_chan, "*"); dcc[i].user = u; putlog(LOG_MISC, "*", "DCC connection: CHAT(file) (%s!%s)", nick, from); dprintf(i, "%s\n", DCC_ENTERPASS); } } return 1; }
// // PacketGet // void PacketGet (void) { int c; socklen_t fromlen; sockaddr_in fromaddress; int node; fromlen = sizeof(fromaddress); c = recvfrom (mysocket, (char*)TransmitBuffer, TRANSMIT_SIZE, 0, (sockaddr *)&fromaddress, &fromlen); node = FindNode (&fromaddress); if (node >= 0 && c == SOCKET_ERROR) { int err = WSAGetLastError(); if (err == WSAECONNRESET) { // The remote node aborted unexpectedly, so pretend it sent an exit packet if (StartScreen != NULL) { StartScreen->NetMessage ("The connection from %s was dropped.\n", players[sendplayer[node]].userinfo.GetName()); } else { Printf("The connection from %s was dropped.\n", players[sendplayer[node]].userinfo.GetName()); } doomcom.data[0] = 0x80; // NCMD_EXIT c = 1; } else if (err != WSAEWOULDBLOCK) { I_Error ("GetPacket: %s", neterror ()); } else { doomcom.remotenode = -1; // no packet return; } } else if (node >= 0 && c > 0) { doomcom.data[0] = TransmitBuffer[0] & ~NCMD_COMPRESSED; if (TransmitBuffer[0] & NCMD_COMPRESSED) { uLongf msgsize = MAX_MSGLEN - 1; int err = uncompress(doomcom.data + 1, &msgsize, TransmitBuffer + 1, c - 1); // Printf("recv %d/%lu\n", c, msgsize + 1); if (err != Z_OK) { Printf("Net decompression failed (zlib error %s)\n", M_ZLibError(err).GetChars()); // Pretend no packet doomcom.remotenode = -1; return; } c = msgsize + 1; } else { // Printf("recv %d\n", c); memcpy(doomcom.data + 1, TransmitBuffer + 1, c - 1); } } else if (c > 0) { //The packet is not from any in-game node, so we might as well discard it. // Don't show the message for disconnect notifications. if (c != 2 || TransmitBuffer[0] != PRE_FAKE || TransmitBuffer[1] != PRE_DISCONNECT) { DPrintf(DMSG_WARNING, "Dropped packet: Unknown host (%s:%d)\n", inet_ntoa(fromaddress.sin_addr), fromaddress.sin_port); } doomcom.remotenode = -1; return; } doomcom.remotenode = node; doomcom.datalength = (short)c; }
static int http_client_connectto(const char *host, int port, struct timeval *timeout) { struct timeval stv, *ptv; __pmHostEnt *servInfo; __pmSockAddr *myAddr; __pmFdSet readyFds, allFds; void *enumIx; int fdFlags[FD_SETSIZE]; int i, fd, sts, maxFd; if ((servInfo = __pmGetAddrInfo(host)) == NULL) { if (pmDebug & DBG_TRACE_HTTP) fprintf(stderr, "HTTP connect(%s, %d): hosterror=%d, ``%s''\n", host, port, hosterror(), hoststrerror()); return -EHOSTUNREACH; } /* * We want to respect the connect timeout that has been configured, but we * may have more than one address to try. Do this by creating a socket for * each address and then using __pmSelectWrite() to wait for one of them to * respond. That way, the timeout is applied to all of the addresses * simultaneously. First, create the sockets, add them to the fd set and * try to establish connectections. */ __pmFD_ZERO(&allFds); maxFd = -1; enumIx = NULL; for (myAddr = __pmHostEntGetSockAddr(servInfo, &enumIx); myAddr != NULL; myAddr = __pmHostEntGetSockAddr(servInfo, &enumIx)) { /* Create a socket */ if (__pmSockAddrIsInet(myAddr)) fd = __pmCreateSocket(); else if (__pmSockAddrIsIPv6(myAddr)) fd = __pmCreateIPv6Socket(); else { if (pmDebug & DBG_TRACE_HTTP) fprintf(stderr, "HTTP connect(%s, %d): bad address family %d\n", host, port, __pmSockAddrGetFamily(myAddr)); fd = -EINVAL; } if (fd < 0) { __pmSockAddrFree(myAddr); continue; /* Try the next address */ } /* Attempt to connect */ fdFlags[fd] = __pmConnectTo(fd, myAddr, port); __pmSockAddrFree(myAddr); if (fdFlags[fd] < 0) { /* * Mark failure in case we fall out the end of the loop * and try next address */ __pmCloseSocket(fd); continue; } /* Add it to the fd set. */ __pmFD_SET(fd, &allFds); if (fd > maxFd) maxFd = fd; } __pmHostEntFree(servInfo); /* If we were unable to open any sockets, then give up. */ if (maxFd == -1) return -ECONNREFUSED; /* FNDELAY and we're in progress - wait on select */ __pmFD_COPY(&readyFds, &allFds); stv = *timeout; ptv = (stv.tv_sec || stv.tv_usec) ? &stv : NULL; sts = __pmSelectWrite(maxFd+1, &readyFds, ptv); /* Figure out what happened. */ if (sts == 0) fd = -ETIMEDOUT; else if (sts < 0) fd = -neterror(); else { /* Scan fd set, find first successfully connected socket (if any). */ fd = -EINVAL; for (i = 0; i <= maxFd; ++i) { if (__pmFD_ISSET(i, &readyFds)) { /* Successful connection? */ sts = __pmConnectCheckError(i); if (sts == 0) { fd = i; break; } fd = -sts; } } } /* Clean up the unused fds. */ for (i = 0; i <= maxFd; ++i) { if (i != fd && __pmFD_ISSET(i, &allFds)) __pmCloseSocket(i); } if (fd < 0) return fd; /* * If we're here, it means we have a valid connection; restore the * flags and make sure this file descriptor is closed if exec() is * called */ return __pmConnectRestoreFlags(fd, fdFlags[fd]); }
int __pmConnectPMCD(pmHostSpec *hosts, int nhosts, int ctxflags, __pmHashCtl *attrs) { int sts = -1; int fd = -1; /* Fd for socket connection to pmcd */ int *ports; int nports; int portIx; int version = -1; int proxyport; pmHostSpec *proxyhost; static int first_time = 1; static pmHostSpec proxy; PM_INIT_LOCKS(); PM_LOCK(__pmLock_libpcp); if (first_time) { /* * One-trip check for use of pmproxy(1) in lieu of pmcd(1), * and to extract the optional environment variables ... * PMCD_PORT, PMPROXY_HOST and PMPROXY_PORT. * We also check for the presense of a certificate database * and load it up if either a user or system (global) DB is * found. */ first_time = 0; load_pmcd_ports(); load_proxy_hostspec(&proxy); } if (hosts[0].nports == 0) { nports = global_nports; ports = global_portlist; } else { nports = hosts[0].nports; ports = hosts[0].ports; } if (proxy.name == NULL && nhosts == 1) { const char *name = (const char *)hosts[0].name; /* * no proxy, connecting directly to pmcd */ PM_UNLOCK(__pmLock_libpcp); sts = -1; /* Try connecting via the local unix domain socket, if requested and supported. */ if (nports == PM_HOST_SPEC_NPORTS_LOCAL || nports == PM_HOST_SPEC_NPORTS_UNIX) { #if defined(HAVE_STRUCT_SOCKADDR_UN) if ((fd = __pmAuxConnectPMCDUnixSocket(name)) >= 0) { if ((sts = __pmConnectHandshake(fd, name, ctxflags, attrs)) < 0) { __pmCloseSocket(fd); } else sts = fd; portIx = -1; /* no port */ } #endif /* * If the connection failed, or is not supported, and the protocol was 'local:', * then try connecting to localhost via the default port(s). */ if (sts < 0) { if (nports == PM_HOST_SPEC_NPORTS_LOCAL) { name = "localhost"; nports = global_nports; ports = global_portlist; sts = -1; /* keep trying */ } else sts = -2; /* no more connection attempts. */ } } /* If still not connected, try via the given host name and ports, if requested. */ if (sts == -1) { for (portIx = 0; portIx < nports; portIx++) { if ((fd = __pmAuxConnectPMCDPort(name, ports[portIx])) >= 0) { if ((sts = __pmConnectHandshake(fd, name, ctxflags, attrs)) < 0) { __pmCloseSocket(fd); } else /* success */ break; } else sts = fd; } } if (sts < 0) { #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_CONTEXT) { char errmsg[PM_MAXERRMSGLEN]; fprintf(stderr, "__pmConnectPMCD(%s): pmcd connection port=", hosts[0].name); for (portIx = 0; portIx < nports; portIx++) { if (portIx == 0) fprintf(stderr, "%d", ports[portIx]); else fprintf(stderr, ",%d", ports[portIx]); } fprintf(stderr, " failed: %s\n", pmErrStr_r(sts, errmsg, sizeof(errmsg))); } #endif return sts; } #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_CONTEXT) { if (portIx >= 0) { fprintf(stderr, "__pmConnectPMCD(%s): pmcd connection port=%d fd=%d PDU version=%u\n", hosts[0].name, ports[portIx], fd, __pmVersionIPC(fd)); } else { fprintf(stderr, "__pmConnectPMCD(%s): pmcd connection path=%s fd=%d PDU version=%u\n", hosts[0].name, name, fd, __pmVersionIPC(fd)); } __pmPrintIPC(); } #endif return fd; } /* * connecting to pmproxy, and then to pmcd ... not a direct * connection to pmcd */ proxyhost = (nhosts > 1) ? &hosts[1] : &proxy; proxyport = (proxyhost->nports > 0) ? proxyhost->ports[0] : PROXY_PORT; for (portIx = 0; portIx < nports; portIx++) { fd = __pmAuxConnectPMCDPort(proxyhost->name, proxyport); if (fd < 0) { #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_CONTEXT) { char errmsg[PM_MAXERRMSGLEN]; fprintf(stderr, "__pmConnectPMCD(%s): proxy to %s port=%d failed: %s \n", hosts[0].name, proxyhost->name, proxyport, pmErrStr_r(-neterror(), errmsg, sizeof(errmsg))); } #endif PM_UNLOCK(__pmLock_libpcp); return fd; } if ((sts = version = negotiate_proxy(fd, hosts[0].name, ports[portIx])) < 0) __pmCloseSocket(fd); else if ((sts = __pmConnectHandshake(fd, proxyhost->name, ctxflags, attrs)) < 0) __pmCloseSocket(fd); else /* success */ break; } if (sts < 0) { #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_CONTEXT) { char errmsg[PM_MAXERRMSGLEN]; fprintf(stderr, "__pmConnectPMCD(%s): proxy connection to %s port=", hosts[0].name, proxyhost->name); for (portIx = 0; portIx < nports; portIx++) { if (portIx == 0) fprintf(stderr, "%d", ports[portIx]); else fprintf(stderr, ",%d", ports[portIx]); } fprintf(stderr, " failed: %s\n", pmErrStr_r(sts, errmsg, sizeof(errmsg))); } #endif PM_UNLOCK(__pmLock_libpcp); return sts; } #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_CONTEXT) { fprintf(stderr, "__pmConnectPMCD(%s): proxy connection host=%s port=%d fd=%d version=%d\n", hosts[0].name, proxyhost->name, ports[portIx], fd, version); } #endif PM_UNLOCK(__pmLock_libpcp); return fd; }
static int pduread(int fd, char *buf, int len, int mode, int timeout) { /* * handle short reads that may split a PDU ... */ int status = 0; int have = 0; __pmFdSet onefd; static int done_default = 0; static struct timeval def_wait = { 10, 0 }; if (timeout == TRACE_TIMEOUT_DEFAULT) { if (!done_default) { double def_timeout; char *timeout_str; char *end_ptr; if ((timeout_str = getenv(TRACE_ENV_REQTIMEOUT)) != NULL) { def_timeout = strtod(timeout_str, &end_ptr); if (*end_ptr != '\0' || def_timeout < 0.0) { status = PMTRACE_ERR_ENVFORMAT; return status; } else { pmtimevalFromReal(def_timeout, &def_wait); } } done_default = 1; } } while (len) { struct timeval wait; /* * either never timeout (i.e. block forever), or timeout */ if (timeout != TRACE_TIMEOUT_NEVER) { if (timeout > 0) { wait.tv_sec = timeout; wait.tv_usec = 0; } else wait = def_wait; __pmFD_ZERO(&onefd); __pmFD_SET(fd, &onefd); status = __pmSelectRead(fd+1, &onefd, &wait); if (status == 0) return PMTRACE_ERR_TIMEOUT; else if (status < 0) { setoserror(neterror()); return status; } } status = (int)__pmRead(fd, buf, len); if (status <= 0) { /* EOF or error */ setoserror(neterror()); return status; } if (mode == -1) /* special case, see __pmtracegetPDU */ return status; have += status; buf += status; len -= status; } return have; }
static int pduread(int fd, char *buf, int len, int part, int timeout) { int socketipc = __pmSocketIPC(fd); int status = 0; int have = 0; int onetrip = 1; struct timeval dead_hand; struct timeval now; if (timeout == -2 /*TIMEOUT_ASYNC*/) return -EOPNOTSUPP; /* * Handle short reads that may split a PDU ... * * The original logic here assumed that recv() would only split a * PDU at a word (__pmPDU) boundary ... with the introduction of * secure connections, SSL and possibly compression all lurking * below the socket covers, this is no longer a safe assumption. * * So, we keep nibbling at the input stream until we have all that * we have requested, or we timeout, or error. */ while (len) { struct timeval wait; #if defined(IS_MINGW) /* cannot select on a pipe on Win32 - yay! */ if (!__pmSocketIPC(fd)) { COMMTIMEOUTS cwait = { 0 }; if (timeout != TIMEOUT_NEVER) cwait.ReadTotalTimeoutConstant = timeout * 1000.0; else cwait.ReadTotalTimeoutConstant = def_timeout * 1000.0; SetCommTimeouts((HANDLE)_get_osfhandle(fd), &cwait); } else #endif /* * either never timeout (i.e. block forever), or timeout */ if (timeout != TIMEOUT_NEVER) { if (timeout > 0) { wait.tv_sec = timeout; wait.tv_usec = 0; } else wait = def_wait; if (onetrip) { /* * Need all parts of the PDU to be received by dead_hand * This enforces a low overall timeout for the whole PDU * (as opposed to just a timeout for individual calls to * recv). A more invasive alternative (better) approach * would see all I/O performed in the main event loop, * and I/O routines transformed to continuation-passing * style. */ gettimeofday(&dead_hand, NULL); dead_hand.tv_sec += wait.tv_sec; dead_hand.tv_usec += wait.tv_usec; while (dead_hand.tv_usec >= 1000000) { dead_hand.tv_usec -= 1000000; dead_hand.tv_sec++; } onetrip = 0; } status = __pmSocketReady(fd, &wait); if (status > 0) { gettimeofday(&now, NULL); if (now.tv_sec > dead_hand.tv_sec || (now.tv_sec == dead_hand.tv_sec && now.tv_usec > dead_hand.tv_usec)) status = 0; } if (status == 0) { if (__pmGetInternalState() != PM_STATE_APPL) { /* special for PMCD and friends * Note, on Linux select would return 'time remaining' * in timeout value, so report the expected timeout */ int tosec, tomsec; if ( timeout != TIMEOUT_NEVER && timeout > 0 ) { tosec = (int)timeout; tomsec = 0; } else { tosec = (int)def_wait.tv_sec; tomsec = 1000*(int)def_wait.tv_usec; } __pmNotifyErr(LOG_WARNING, "pduread: timeout (after %d.%03d " "sec) while attempting to read %d " "bytes out of %d in %s on fd=%d", tosec, tomsec, len - have, len, part == HEADER ? "HDR" : "BODY", fd); } return PM_ERR_TIMEOUT; } else if (status < 0) { char errmsg[PM_MAXERRMSGLEN]; __pmNotifyErr(LOG_ERR, "pduread: select() on fd=%d: %s", fd, netstrerror_r(errmsg, sizeof(errmsg))); setoserror(neterror()); return status; } } if (socketipc) { status = __pmRecv(fd, buf, len, 0); setoserror(neterror()); } else { status = read(fd, buf, len); } __pmOverrideLastFd(fd); if (status < 0) /* error */ return status; else if (status == 0) /* return what we have, or nothing */ break; have += status; buf += status; len -= status; #ifdef PCP_DEBUG if ((pmDebug & DBG_TRACE_PDU) && (pmDebug & DBG_TRACE_DESPERATE)) { fprintf(stderr, "pduread(%d, ...): have %d, last read %d, still need %d\n", fd, have, status, len); } #endif } return have; }
static void ClientLoop(void) { int i, fd, sts; int maxFd; int checkAgents; int reload_ns = 0; __pmFdSet readableFds; for (;;) { /* Figure out which file descriptors to wait for input on. Keep * track of the highest numbered descriptor for the select call. */ readableFds = clientFds; maxFd = maxClientFd + 1; /* If an agent was not ready, it may send an ERROR PDU to indicate it * is now ready. Add such agents to the list of file descriptors. */ checkAgents = 0; for (i = 0; i < nAgents; i++) { AgentInfo *ap = &agent[i]; if (ap->status.notReady) { fd = ap->outFd; __pmFD_SET(fd, &readableFds); if (fd > maxFd) maxFd = fd + 1; checkAgents = 1; if (pmDebug & DBG_TRACE_APPL0) __pmNotifyErr(LOG_INFO, "not ready: check %s agent on fd %d (max = %d)\n", ap->pmDomainLabel, fd, maxFd); } } sts = __pmSelectRead(maxFd, &readableFds, NULL); if (sts > 0) { if (pmDebug & DBG_TRACE_APPL0) for (i = 0; i <= maxClientFd; i++) if (__pmFD_ISSET(i, &readableFds)) fprintf(stderr, "DATA: from %s (fd %d)\n", FdToString(i), i); __pmServerAddNewClients(&readableFds, CheckNewClient); if (checkAgents) reload_ns = HandleReadyAgents(&readableFds); HandleClientInput(&readableFds); } else if (sts == -1 && neterror() != EINTR) { __pmNotifyErr(LOG_ERR, "ClientLoop select: %s\n", netstrerror()); break; } if (restart) { restart = 0; reload_ns = 1; SignalRestart(); } if (reload_ns) { reload_ns = 0; SignalReloadPMNS(); } if (timeToDie) { SignalShutdown(); break; } if (AgentDied) { AgentDied = 0; for (i = 0; i < nAgents; i++) { if (!agent[i].status.connected) mapdom[agent[i].pmDomainId] = nAgents; } } } }