static enum proxy_status socks4a_connect(struct host *h, const char *target_host, int target_port) { char handshake[8]; int rBuf; target_port = platform_htons(target_port); _raw_host_connect(h, conf->socks_host, conf->socks_port); if (!__send(h, "\4\1", 2)) return PROXY_SEND_ERROR; if (!__send(h, &target_port, 2)) return PROXY_SEND_ERROR; if (!__send(h, "\0\0\0\1anonymous", 14)) return PROXY_SEND_ERROR; if (!__send(h, target_host, strlen(target_host))) return PROXY_SEND_ERROR; if (!__send(h, "\0", 1)) return PROXY_SEND_ERROR; rBuf = __recv(h, handshake, 8); if (rBuf == -1) return PROXY_CONNECTION_FAILED; if (handshake[1] != 90) return PROXY_HANDSHAKE_FAILED; return PROXY_SUCCESS; }
static enum proxy_status socks5_connect(struct host *h, struct addrinfo *ai_data) { /* This handshake is more complicated than SOCKS4 or 4a... * and we're also only supporting none or user/password auth. */ char handshake[10]; int rBuf; _raw_host_connect(h, conf->socks_host, conf->socks_port); // Version[0x05]|Number of auth methods|auth methods if (!__send(h, "\5\1\0", 3)) return PROXY_SEND_ERROR; rBuf = __recv(h, handshake, 2); if (rBuf == -1) return PROXY_CONNECTION_FAILED; if (handshake[0] != 0x5) return PROXY_HANDSHAKE_FAILED; #ifdef CONFIG_IPV6 if (ai_data->ai_family == AF_INET6) return PROXY_ADDRESS_TYPE_UNSUPPORTED; #endif // Version[0x05]|Command|0x00|address type|destination|port if (!__send(h, "\5\1\0\1", 4)) return PROXY_SEND_ERROR; if (!__send(h, ai_data->ai_addr->sa_data+2, 4)) return PROXY_SEND_ERROR; if (!__send(h, ai_data->ai_addr->sa_data, 2)) return PROXY_SEND_ERROR; rBuf = __recv(h, handshake, 10); if (rBuf == -1) return PROXY_CONNECTION_FAILED; switch (handshake[1]) { case 0x0: return PROXY_SUCCESS; case 0x1: case 0x7: return PROXY_UNKNOWN_ERROR; case 0x2: return PROXY_ACCESS_DENIED; case 0x3: case 0x4: case 0x6: return PROXY_REFLECTION_FAILED; case 0x5: return PROXY_TARGET_REFUSED; case 0x8: return PROXY_ADDRESS_TYPE_UNSUPPORTED; default: return PROXY_UNKNOWN_ERROR; } }
bool_ CTransaction::handlePushMessage(ub1_ ornType, ub8_ ornId, ub8_ ornExtId, ub8_ messageId, const c1_ *json, ub2_ size, ub8_ timestamp) { Message::TPDUPushMsg msg; msg.header.size = sizeof(Message::TPDUPushMsg); msg.header.type = Message::MT_SERVICE; msg.header.cmd = Message::MC_PUSH_MSG; msg.header.ver = Config::App::PROTOCOL_VERSION; msg.header.lang = Message::ML_CN; msg.header.seq = 0; msg.header.stmp = CBase::now(); msg.header.ext = 0; msg.ornType = ornType; msg.ornId = ornId; msg.ornExtId = ornExtId; msg.messageId = messageId; memset(msg.json, 0, Size::JSON); assert(Length::JSON >= size); strncpy(msg.json, json, Length::JSON); bool_ ret = __send((Message::TMsg *) &msg, true_v); if (true_v == ret) { _lastUpdate = timestamp; } return ret; }
// Called by CNodeGroup thread bool_ CTransaction::__onSendMsg(const Message::TPDUSendMsg *msg) { log_debug("[%p]CTransaction::onSendMsg: current status-%d", this, _status); if (ETransactionStatus::READY != _status) { return over(ETransactionExitReason::WRONG_STATUS); } Message::TPDUSendMsgAck msgAck; memcpy(&msgAck.header, &msg->header, sizeof(Message::THeader)); msgAck.header.size = sizeof(Message::TPDUSendMsgAck); msgAck.header.type |= Message::MT_SIGN_ACK; msgAck.header.stmp = CBase::now(); msgAck.ack.code = 0; if (false_v == _node->getGroup()->ro().sendMessage(this, msg, msgAck.messageId)) { msgAck.ack.code = (ub2_)ETransactionExitReason::NO_DESTINATION_FOUND; } __send((Message::TMsg *) &msgAck, false_v); return true_v; }
static ssize_t http_send_line(struct host *h, const char *message) { char line[LINE_BUF_LEN]; ssize_t len; snprintf(line, LINE_BUF_LEN, "%s\r\n", message); len = (ssize_t)strlen(line); if(!__send(h, line, len)) len = -HOST_SEND_FAILED; return len; }
static enum proxy_status socks4_connect(struct host *h, struct addrinfo *ai_data) { char handshake[8]; int rBuf; _raw_host_connect(h, conf->socks_host, conf->socks_port); if (!__send(h, "\4\1", 2)) return PROXY_SEND_ERROR; if (!__send(h, ai_data->ai_addr->sa_data, 6)) return PROXY_SEND_ERROR; if (!__send(h, "anonymous\0", 10)) return PROXY_SEND_ERROR; rBuf = __recv(h, handshake, 8); if (rBuf == -1) return PROXY_CONNECTION_FAILED; if (handshake[1] != 90) return PROXY_HANDSHAKE_FAILED; return PROXY_SUCCESS; }
int __get_product(product_name name, Product * productp){ char toSend[sizeof(product_name_msg)]; msg_type resp_type; char resp_body[sizeof(product_resp)]; __connect(); msg_serialize_product_name_msg(__get_id(), GET_PRODUCT, name, toSend); __send(toSend, sizeof(product_name_msg)); __recv(&resp_type, sizeof(msg_type)); if (resp_type == OK_RESP) { __recv(resp_body, sizeof(Product)); msg_deserialize_product(resp_body, productp); __disconnect(); return OK; } return __handle_not_ok_resp(resp_type); }
int __write_product(product_name name, int quantity){ char toSend[sizeof(product_msg)]; msg_type resp_type; char resp_body[sizeof(error_resp)]; int code; __connect(); msg_serialize_product_msg(__get_id(), WRITE_PRODUCT, product_new(name, quantity), toSend); __send(toSend, sizeof(product_msg)); __recv(&resp_type, sizeof(msg_type)); if (resp_type == OK_RESP) { __recv(resp_body, sizeof(int)); msg_deserialize_code(resp_body, &code); __disconnect(); return OK; } return __handle_not_ok_resp(resp_type); }
void __vsyslog_chk(int pri, int flag, const char *fmt, va_list ap) { struct tm now_tm; time_t now; int fd; FILE *f; char *buf = 0; size_t bufsize = 0; size_t msgoff; #ifndef NO_SIGPIPE struct sigaction action, oldaction; int sigpipe; #endif int saved_errno = errno; char failbuf[3 * sizeof (pid_t) + sizeof "out of memory []"]; #define INTERNALLOG LOG_ERR|LOG_CONS|LOG_PERROR|LOG_PID /* Check for invalid bits. */ if (pri & ~(LOG_PRIMASK|LOG_FACMASK)) { syslog(INTERNALLOG, "syslog: unknown facility/priority: %x", pri); pri &= LOG_PRIMASK|LOG_FACMASK; } /* Check priority against setlogmask values. */ if ((LOG_MASK (LOG_PRI (pri)) & LogMask) == 0) return; /* Set default facility if none specified. */ if ((pri & LOG_FACMASK) == 0) pri |= LogFacility; /* Build the message in a memory-buffer stream. */ f = __open_memstream (&buf, &bufsize); if (f == NULL) { /* We cannot get a stream. There is not much we can do but emitting an error messages. */ char numbuf[3 * sizeof (pid_t)]; char *nump; char *endp = __stpcpy (failbuf, "out of memory ["); pid_t pid = __getpid (); nump = numbuf + sizeof (numbuf); /* The PID can never be zero. */ do *--nump = '0' + pid % 10; while ((pid /= 10) != 0); endp = __mempcpy (endp, nump, (numbuf + sizeof (numbuf)) - nump); *endp++ = ']'; *endp = '\0'; buf = failbuf; bufsize = endp - failbuf; msgoff = 0; } else { __fsetlocking (f, FSETLOCKING_BYCALLER); fprintf (f, "<%d>", pri); (void) time (&now); f->_IO_write_ptr += __strftime_l (f->_IO_write_ptr, f->_IO_write_end - f->_IO_write_ptr, "%h %e %T ", __localtime_r (&now, &now_tm), _nl_C_locobj_ptr); msgoff = ftell (f); if (LogTag == NULL) LogTag = __progname; if (LogTag != NULL) __fputs_unlocked (LogTag, f); if (LogStat & LOG_PID) fprintf (f, "[%d]", (int) __getpid ()); if (LogTag != NULL) { putc_unlocked (':', f); putc_unlocked (' ', f); } /* Restore errno for %m format. */ __set_errno (saved_errno); /* We have the header. Print the user's format into the buffer. */ if (flag == -1) vfprintf (f, fmt, ap); else __vfprintf_chk (f, flag, fmt, ap); /* Close the memory stream; this will finalize the data into a malloc'd buffer in BUF. */ fclose (f); } /* Output to stderr if requested. */ if (LogStat & LOG_PERROR) { struct iovec iov[2]; struct iovec *v = iov; v->iov_base = buf + msgoff; v->iov_len = bufsize - msgoff; /* Append a newline if necessary. */ if (buf[bufsize - 1] != '\n') { ++v; v->iov_base = (char *) "\n"; v->iov_len = 1; } __libc_cleanup_push (free, buf == failbuf ? NULL : buf); /* writev is a cancellation point. */ (void)__writev(STDERR_FILENO, iov, v - iov + 1); __libc_cleanup_pop (0); } /* Prepare for multiple users. We have to take care: open and write are cancellation points. */ struct cleanup_arg clarg; clarg.buf = buf; clarg.oldaction = NULL; __libc_cleanup_push (cancel_handler, &clarg); __libc_lock_lock (syslog_lock); #ifndef NO_SIGPIPE /* Prepare for a broken connection. */ memset (&action, 0, sizeof (action)); action.sa_handler = sigpipe_handler; sigemptyset (&action.sa_mask); sigpipe = __sigaction (SIGPIPE, &action, &oldaction); if (sigpipe == 0) clarg.oldaction = &oldaction; #endif /* Get connected, output the message to the local logger. */ if (!connected) openlog_internal(LogTag, LogStat | LOG_NDELAY, 0); /* If we have a SOCK_STREAM connection, also send ASCII NUL as a record terminator. */ if (LogType == SOCK_STREAM) ++bufsize; if (!connected || __send(LogFile, buf, bufsize, send_flags) < 0) { if (connected) { /* Try to reopen the syslog connection. Maybe it went down. */ closelog_internal (); openlog_internal(LogTag, LogStat | LOG_NDELAY, 0); } if (!connected || __send(LogFile, buf, bufsize, send_flags) < 0) { closelog_internal (); /* attempt re-open next time */ /* * Output the message to the console; don't worry * about blocking, if console blocks everything will. * Make sure the error reported is the one from the * syslogd failure. */ if (LogStat & LOG_CONS && (fd = __open(_PATH_CONSOLE, O_WRONLY|O_NOCTTY, 0)) >= 0) { __dprintf (fd, "%s\r\n", buf + msgoff); (void)__close(fd); } } } #ifndef NO_SIGPIPE if (sigpipe == 0) __sigaction (SIGPIPE, &oldaction, (struct sigaction *) NULL); #endif /* End of critical section. */ __libc_cleanup_pop (0); __libc_lock_unlock (syslog_lock); if (buf != failbuf) free (buf); }
bool_ CTransaction::__onTimer(const Message::TPDUOnTimer *msg) { if (_keepLiveTimerId == msg->timerId) { if (_status != (ETransactionStatus)msg->parameter) { log_debug("[%p]CTransaction::onTimer: timer status(%d) != " "current(%d) status", this, msg->parameter, _status); return true_v; } if (ETransactionStatus::CONNECTED == _status) { log_debug("[%p]CTransaction::onTimer: waiting handshake timeout, " "current status-%d", this, _status); return over(ETransactionExitReason::TIME_OUT); } else if (ETransactionStatus::READY == _status) { if (false_v == _heartbeat) { log_debug("[%p]CTransaction::onTimer: heartbeat timeout, " "current status-%d", this, _status); return over(ETransactionExitReason::TIME_OUT); } else { Message::TPDUHeartBeat message; message.header.size = sizeof(Message::TPDUHeartBeat); message.header.type = Message::MT_CONTROL; message.header.cmd = Message::MC_HEART_BEAT; message.header.ver = Config::App::PROTOCOL_VERSION; message.header.lang = 1; message.header.seq = 0; __send((Message::TMsg *) &message, false_v); _heartbeat = false_v; } } else { assert(false_v); } } else { if (ETransactionStatus::READY != _status) { log_debug("[%p]CTransaction::onTimer: seq(%u)'s status(%d) is " "expected, but now it's status(%d)", this, msg->parameter, ETransactionStatus::READY, _status); return true_v; } ub4_ seq = (ub4_) msg->parameter; MapSeq2Timer::iterator pos = _mapSeq2Timer.find(seq); if (_mapSeq2Timer.end() != pos) { log_debug("[%p]CTransaction::onTimer: waitting ack timeout, " "current status-%d, seq-%u", this, _status, seq); return over(ETransactionExitReason::TIME_OUT); } else { assert(false_v); } } return true_v; }
bool_ CTransaction::__onStart(const Message::TPDUHandShake* msg) { log_debug("[%p]CTransaction::onStart: current status-%d", this, _status); if (ETransactionStatus::CONNECTED != _status) { return over(ETransactionExitReason::WRONG_STATUS); } assert(_keepLiveTimerId); CTransactionManager::instance()->killTimer(_keepLiveTimerId); _keepLiveTimerId = 0; Message::TPDUHandShakeAck msgAck; memcpy(&msgAck, msg, sizeof(Message::THeader)); msgAck.header.size = sizeof(Message::TPDUHandShakeAck); msgAck.header.type |= Message::MT_SIGN_ACK; msgAck.ack.code = 0; if (Config::App::BASE_BUILD > msg->build) { log_notice("[%p]CTransaction::onStart: client version with %u or above" " is necessary, now it's %u", this, Config::App::BASE_BUILD, msg->build); msgAck.ack.code = (ub2_)ETransactionExitReason::CLIENT_TOO_OLD; __send((Message::TMsg *) &msgAck, false_v); return over(ETransactionExitReason::CLIENT_TOO_OLD); } memcpy(_sessionId, msg->sessionId, Size::SESSION_ID); _id = _node->getGroup()->ro().verifyHandshake(_sessionId); if (0 == _id) { log_notice("[%p]CTransaction::onStart: cannot find corresponding " "sessionId-%s", this, _sessionId); memset(_sessionId, 0, Size::SESSION_ID); _id = 0; msgAck.ack.code = (ub2_)ETransactionExitReason::NO_THE_SESSION_FOUND; __send((Message::TMsg *) &msgAck, false_v); return over(ETransactionExitReason::NO_THE_SESSION_FOUND); } if (false_v == CTransactionManager::instance()->registerTransaction(this)) { log_notice("[%p]CTransaction::onStart: there is an transaction with " "the same sessionId-%s and id-%lu", this, _sessionId, _id); memset(_sessionId, 0, Size::SESSION_ID); _id = 0; msgAck.ack.code = (ub2_)ETransactionExitReason::SAME_SESSION_ID; __send((Message::TMsg *) &msgAck, false_v); return over(ETransactionExitReason::SAME_SESSION_ID); } _status = ETransactionStatus::READY; msgAck.ack.code = 0; _lastUpdate = msg->lastUpdate; if (true_v == __send((Message::TMsg *) &msgAck, false_v)) { _heartbeat = true_v; _keepLiveTimerId = CTransactionManager::instance()->setTimer( Config::App::HEARTBEAT_INTERVAL, this, (obj_) _status, 0); if (0 == _keepLiveTimerId) { return over(ETransactionExitReason::NO_MORE_TIMER); } } return true_v; }
boolean host_handle_http_request(struct host *h) { const char *mime_type = "application/octet-stream"; char buffer[LINE_BUF_LEN], *buf = buffer; char *cmd_type, *path, *proto; enum host_status ret; size_t path_len; FILE *f; if(http_recv_line(h, buffer, LINE_BUF_LEN) < 0) { warn("Failed to receive HTTP request\n"); return false; } cmd_type = strsep(&buf, " "); if(!cmd_type) return false; if(strcmp(cmd_type, "GET") != 0) return false; path = strsep(&buf, " "); if(!path) return false; proto = strsep(&buf, " "); if(!proto) return false; if(strncmp("HTTP/1.1", proto, 8) != 0) { warn("Client must support HTTP 1.1, rejecting\n"); return false; } if(!http_skip_headers(h)) { warn("Failed to skip HTTP headers\n"); return false; } path++; debug("Received request for '%s'\n", path); f = fopen(path, "rb"); if(!f) { warn("Failed to open file '%s', sending 404\n", path); snprintf(buffer, LINE_BUF_LEN, "HTTP/1.1 404 Not Found\r\n" "Content-Length: %zd\r\n" "Content-Type: text/html\r\n" "Connection: close\r\n\r\n", strlen(resp_404)); if(__send(h, buffer, strlen(buffer))) { if(!__send(h, resp_404, strlen(resp_404))) warn("Failed to send 404 payload\n"); } else warn("Failed to send 404 status code\n"); return false; } path_len = strlen(path); if(path_len >= 4 && strcasecmp(&path[path_len - 4], ".txt") == 0) mime_type = "text/plain"; ret = host_send_file(h, f, mime_type); if(ret != HOST_SUCCESS) { warn("Failed to send file '%s' over HTTP (error %d)\n", path, ret); return false; } return true; }
enum host_status host_send_file(struct host *h, FILE *file, const char *mime_type) { boolean mid_deflate = false; char line[LINE_BUF_LEN]; uint32_t crc, uSize; z_stream stream; long size; // Tell the client that we're going to use HTTP/1.1 features if(http_send_line(h, "HTTP/1.1 200 OK") < 0) return -HOST_SEND_FAILED; /* To bring ourselves into complete HTTP 1.1 compliance, send * some headers that we know our client doesn't actually need. */ if(http_send_line(h, "Accept-Ranges: bytes") < 0) return -HOST_SEND_FAILED; if(http_send_line(h, "Vary: Accept-Encoding") < 0) return -HOST_SEND_FAILED; // Always zlib deflate content; keeps code simple if(http_send_line(h, "Content-Encoding: gzip") < 0) return -HOST_SEND_FAILED; // We'll just send everything chunked, unconditionally if(http_send_line(h, "Transfer-Encoding: chunked") < 0) return -HOST_SEND_FAILED; // Pass along a type hint for the client (mandatory sanity check for MZX) snprintf(line, LINE_BUF_LEN, "Content-Type: %s", mime_type); line[LINE_BUF_LEN - 1] = 0; if(http_send_line(h, line) < 0) return -HOST_SEND_FAILED; // Terminate the headers with a blank line if(http_send_line(h, "") < 0) return -HOST_SEND_FAILED; // Initialize CRC for GZIP footer crc = crc32(0L, Z_NULL, 0); // Record uncompressed size for GZIP footer size = ftell_and_rewind(file); uSize = (uint32_t)size; if(size < 0) return -HOST_FREAD_FAILED; while(true) { int deflate_offset = 0, ret = Z_OK, deflate_flag = Z_SYNC_FLUSH; char block[BLOCK_SIZE], zblock[BLOCK_SIZE]; size_t block_size; /* Read a block from the disk source and compute a CRC32 on the * fly. This CRC will be dumped at the end of the deflated data * and is required for RFC 1952 compliancy. */ block_size = fread(block, 1, BLOCK_SIZE, file); crc = crc32(crc, (Bytef *)block, block_size); /* The fread() above pretty much guarantees that block_size will * be BLOCK_SIZE up to the final block. However, fread() also * returns a short count if there was an I/O error, and we must * detect this. If it's legitimately the final block, give the * compressor this information. */ if(block_size != BLOCK_SIZE) { if(!feof(file)) return -HOST_FREAD_FAILED; deflate_flag = Z_FINISH; } /* We exhausted input at a block boundary. This is unlikely, * but in the event that it happens we can simply ignore * the deflate stage and write out the terminal chunk signature. */ if(block_size == 0) break; /* Regardless of whether we are initializing the compressor in * the next section or not, we always have BLOCK_SIZE aligned * input data available. */ stream.avail_in = block_size; stream.next_in = (Bytef *)block; if(!mid_deflate) { deflate_offset = zlib_forge_gzip_header(zblock); stream.avail_out = BLOCK_SIZE - (unsigned long)deflate_offset; stream.next_out = (Bytef *)&zblock[deflate_offset]; stream.zalloc = Z_NULL; stream.zfree = Z_NULL; stream.opaque = Z_NULL; ret = deflateInit2(&stream, Z_BEST_COMPRESSION, Z_DEFLATED, -MAX_WBITS, 8, Z_DEFAULT_STRATEGY); if(ret != Z_OK) return -HOST_ZLIB_DEFLATE_FAILED; mid_deflate = true; } else { stream.avail_out = BLOCK_SIZE; stream.next_out = (Bytef *)zblock; } while(true) { unsigned long chunk_size; // Deflate a chunk of the input (partially or fully) ret = deflate(&stream, deflate_flag); if(ret != Z_OK && ret != Z_STREAM_END) return -HOST_ZLIB_INFLATE_FAILED; // Compute chunk length (final chunk includes GZIP footer) chunk_size = BLOCK_SIZE - stream.avail_out; if(ret == Z_STREAM_END) chunk_size += 2 * sizeof(uint32_t); // Dump compressed chunk length snprintf(line, LINE_BUF_LEN, "%lx", chunk_size); if(http_send_line(h, line) < 0) return -HOST_SEND_FAILED; // Send the compressed output block over the socket if(!__send(h, zblock, BLOCK_SIZE - stream.avail_out)) return -HOST_SEND_FAILED; /* We might not have finished the entire stream, but the * available input is likely to have been exhausted. With * Z_SYNC_FLUSH this will commonly result in zero bytes * remaining in the input source. Additionally, if this is * the final chunk (and Z_FINISH was flagged), Z_STREAM_END * will be set. In either case, we must break out. */ if((ret == Z_OK && stream.avail_in == 0) || ret == Z_STREAM_END) break; // Output has been flushed; start over for the remaining input (if any) stream.avail_out = BLOCK_SIZE; stream.next_out = (Bytef *)zblock; } /* Z_FINISH was flagged, stream ended * Terminate compression */ if(ret == Z_STREAM_END) { // Free any zlib allocated resources deflateEnd(&stream); // Write out GZIP `CRC32' footer if(!__send(h, &crc, sizeof(uint32_t))) return -HOST_SEND_FAILED; // Write out GZIP `ISIZE' footer if(!__send(h, &uSize, sizeof(uint32_t))) return -HOST_SEND_FAILED; mid_deflate = false; } // Newline after chunk's data if(http_send_line(h, "") < 0) return -HOST_SEND_FAILED; // Final block; can break out if(block_size != BLOCK_SIZE) break; } // Terminal chunk signature, so called "trailer" if(http_send_line(h, "0") < 0) return -HOST_SEND_FAILED; // Post-trailer newline if(http_send_line(h, "") < 0) return -HOST_SEND_FAILED; return HOST_SUCCESS; }
boolean host_send_raw(struct host *h, const char *buffer, unsigned int len) { return __send(h, buffer, len); }
static void __vsyslogex_chk(int pri, int flag, pid_t cpid, pid_t ctid, const char *fmt, va_list ap) { struct tm now_tm; time_t now; int fd; FILE *f; char *buf = 0; size_t bufsize = 0; size_t prioff, msgoff; #ifndef NO_SIGPIPE struct sigaction action, oldaction; int sigpipe; #endif int saved_errno = errno; char failbuf[3 * sizeof (pid_t) + sizeof "out of memory []"]; const int LogMask = setlogmask(0); #ifdef _DEBUGFLAGS_H_ { static unsigned int registered = 0; if (unlikely(0 == registered)) { registered = 1; /* dirty work around to avoid deadlock: syslogex->register->syslogex */ registered = (registerLibraryDebugFlags(&debugFlags) == EXIT_SUCCESS); } } #endif /*_DEBUGFLAGS_H_*/ #define INTERNALLOG LOG_ERR|LOG_CONS|LOG_PERROR|LOG_PID /* Check for invalid bits. */ if (unlikely(pri & ~(LOG_PRIMASK | LOG_FACMASK))) { /*syslog(INTERNALLOG, "syslog: unknown facility/priority: %x", pri);*/ WARNING_MSG("unknown facility/priority: %x", pri); pri &= LOG_PRIMASK | LOG_FACMASK; } /* Check priority against setlogmask values. */ if (unlikely((LOG_MASK(LOG_PRI(pri)) & LogMask) == 0)) return; /* Set default facility if none specified. */ if (unlikely((pri & LOG_FACMASK) == 0)) pri |= LogFacility; /* Build the message in a memory-buffer stream. */ f = open_memstream(&buf, &bufsize); if (unlikely(f == NULL)) { /* We cannot get a stream. There is not much we can do but emitting an error messages with the Process ID. */ char numbuf[3 * sizeof (pid_t)]; char *nump; char *endp = __stpcpy(failbuf, "out of memory ["); pid_t pid = getpid(); nump = numbuf + sizeof (numbuf); /* The PID can never be zero. */ do { *--nump = '0' + pid % 10; } while ((pid /= 10) != 0); endp = mempcpy((void*) endp, (const void*) nump, (size_t) ((numbuf + sizeof (numbuf)) - nump)); *endp++ = ']'; *endp = '\0'; buf = failbuf; bufsize = endp - failbuf; msgoff = 0; } else { __fsetlocking(f, FSETLOCKING_BYCALLER); prioff = fprintf(f, "<%d>", pri); (void) time(&now); f->_IO_write_ptr += strftime(f->_IO_write_ptr, f->_IO_write_end - f->_IO_write_ptr, "%h %e %T ", localtime_r(&now, &now_tm)); /*f->_IO_write_ptr += strftime_l (f->_IO_write_ptr, f->_IO_write_end - f->_IO_write_ptr, "%h %e %T ", localtime_r (&now, &now_tm));*/ msgoff = ftell(f); if (LogTag == NULL) LogTag = __progname; if (LogTag != NULL) fputs_unlocked(LogTag, f); if (LogStat & LOG_PID) { const pid_t pid = ((0 == cpid) ? getpid() : cpid); if (LogStat & LOG_TID) { const pid_t tid = ((0 == ctid) ? gettid() : ctid); fprintf(f, "[%d:%d]", (int) pid, (int) tid); } else { fprintf(f, "[%d]", (int) pid); } } if (LogStat & LOG_RDTSC) { const unsigned long long int t = rdtsc(); fprintf(f, "(%llu)", t); } /* (LogStat & LOG_RDTSC) */ if (LogStat & LOG_CLOCK) { #if HAVE_CLOCK_GETTIME struct timespec timeStamp; if (clock_gettime(CLOCK_MONOTONIC,&timeStamp) == 0) { fprintf(f,"(%lu.%.9d)",timeStamp.tv_sec,timeStamp.tv_nsec); } else { const int error = errno; ERROR_MSG("clock_gettime CLOCK_MONOTONIC error %d (%m)",error); } #else static unsigned int alreadyPrinted = 0; if (unlikely(0 == alreadyPrinted)) { ERROR_MSG("clock_gettime not available on this system"); alreadyPrinted = 1; } #endif } /* (LogStat & LOG_CLOCK) */ if (LogStat & LOG_LEVEL) { switch (LOG_PRI(pri)) { case LOG_EMERG: fprintf(f, "[EMERG]"); break; case LOG_ALERT: fprintf(f, "[ALERT]"); break; case LOG_CRIT: fprintf(f, "[CRIT]"); break; case LOG_ERR: fprintf(f, "[ERROR]"); break; case LOG_WARNING: fprintf(f, "[WARNING]"); break; case LOG_NOTICE: fprintf(f, "[NOTICE]"); break; case LOG_INFO: fprintf(f, "[INFO]"); break; case LOG_DEBUG: fprintf(f, "[DEBUG]"); break; } /* switch(LOG_PRI(pri))*/ } /* (LogStat & LOG_LEVEL) */ if (LogTag != NULL) { putc_unlocked(':', f); putc_unlocked(' ', f); } /* Restore errno for %m format. */ __set_errno(saved_errno); /* We have the header. Print the user's format into the buffer. */ if (flag == -1) { vfprintf(f, fmt, ap); } else { __vfprintf_chk(f, flag, fmt, ap); } /* Close the memory stream; this will finalize the data into a malloc'd buffer in BUF. */ fclose(f); } /* Output to stderr if requested. */ if (LogStat & LOG_PERROR) { struct iovec iov[2]; register struct iovec *v = iov; v->iov_base = buf + msgoff; v->iov_len = bufsize - msgoff; /* Append a newline if necessary. */ if (buf[bufsize - 1] != '\n') { ++v; v->iov_base = (char *) "\n"; v->iov_len = 1; } pthread_cleanup_push(free, buf == failbuf ? NULL : buf); /* writev is a cancellation point. */ (void) writev(STDERR_FILENO, iov, v - iov + 1); pthread_cleanup_pop(0); } /* Prepare for multiple users. We have to take care: open and write are cancellation points. */ struct cleanup_arg clarg; clarg.buf = buf; clarg.oldaction = NULL; pthread_cleanup_push(cancel_handler, &clarg); pthread_mutex_lock(&syslogex_lock); #ifndef NO_SIGPIPE /* Prepare for a broken connection. */ memset(&action, 0, sizeof (action)); action.sa_handler = sigpipe_handler; sigemptyset(&action.sa_mask); sigpipe = __sigaction(SIGPIPE, &action, &oldaction); if (sigpipe == 0) clarg.oldaction = &oldaction; #endif /* Get connected, output the message to the local logger. */ if (!connected) { openlog_internal(LogTag, LogStat | LOG_NDELAY, 0); } /* If we have a SOCK_STREAM connection, also send ASCII NUL as a record terminator. */ if (LogType == SOCK_STREAM) { ++bufsize; } if (!connected || __send(LogFile, buf, bufsize, send_flags) < 0) { if (connected) { /* Try to reopen the syslog connection. Maybe it went down. */ closelog_internal(); openlog_internal(LogTag, LogStat | LOG_NDELAY, 0); } if (!connected || __send(LogFile, buf, bufsize, send_flags) < 0) { closelog_internal(); /* attempt re-open next time */ /* * Output the message to the console; don't worry * about blocking, if console blocks everything will. * Make sure the error reported is the one from the * syslogd failure. */ if (LogStat & LOG_CONS && (fd = __open(_PATH_CONSOLE, O_WRONLY | O_NOCTTY, 0)) >= 0) { dprintf(fd, "%s\r\n", buf + msgoff); (void) __close(fd); } } } #ifndef NO_SIGPIPE if (sigpipe == 0) __sigaction(SIGPIPE, &oldaction, (struct sigaction *) NULL); #endif /* End of critical section. */ pthread_cleanup_pop(0); pthread_mutex_unlock(&syslogex_lock); if (buf != failbuf) { free(buf); } }
int res_send(struct SocketBase * libPtr, const char * buf, int buflen, char * answer, int anslen) { register int n; int try, v_circuit, resplen, nscount; int gotsomewhere = 0, connected = 0; int connreset = 0; u_short id, len; char *cp; fd_set dsmask; struct timeval timeout; struct in_addr *ns; struct sockaddr_in host; HEADER *hp = (HEADER *) buf; HEADER *anhp = (HEADER *) answer; u_char terrno = ETIMEDOUT; #define JUNK_SIZE 512 char junk[JUNK_SIZE]; /* buffer for trash data */ #if defined(__AROS__) D(bug("[AROSTCP](res_send.c) res_send()\n")); D(bug("[AROSTCP](res_send.c) res_send: using socket %d\n", res_sock)); #endif #ifdef RES_DEBUG printf("res_send()\n"); __p_query(buf, libPtr); #endif /* RES_DEBUG */ v_circuit = (_res.options & RES_USEVC) || buflen > PACKETSZ; id = hp->id; /* * Send request, RETRY times, or until successful */ for (try = 0; try < _res.retry; try++) { #if defined(__AROS__) D(bug("[AROSTCP](res_send.c) res_send: Attempt %d\n", try)); #endif nscount = 0; DRES(Printf("Retry #%ld\n",try);) for (ns = _res.nsaddr_list; ns->s_addr; ns++) { nscount++; #if defined(__AROS__) D(bug("[AROSTCP](res_send.c) res_send: Querying server #%ld address = %s\n", nscount, __inet_ntoa(ns->s_addr, libPtr))); #endif #ifdef RES_DEBUG Printf("Querying server #%ld address = %s\n", nscount, __Inet_NtoA(ns->s_addr, libPtr)); #endif /* RES_DEBUG */ host.sin_len = sizeof(host); host.sin_family = AF_INET; host.sin_port = htons(NAMESERVER_PORT); host.sin_addr.s_addr = ns->s_addr; aligned_bzero_const(&host.sin_zero, sizeof(host.sin_zero)); usevc: if (v_circuit) { #if defined(__AROS__) D(bug("[AROSTCP](res_send.c) res_send: Using v_circuit\n")); #endif int truncated = 0; /* * Use virtual circuit; * at most one attempt per server. */ try = _res.retry; if (res_sock < 0) { res_sock = __socket(AF_INET, SOCK_STREAM, 0, libPtr); if (res_sock < 0) { #if defined(__AROS__) D(bug("[AROSTCP](res_send.c) res_send: Failed to create socket!!\n")); terrno = readErrnoValue(libPtr); #endif #ifdef RES_DEBUG Perror("socket (vc)"); #endif /* RES_DEBUG */ continue; } #if defined(__AROS__) D(bug("[AROSTCP](res_send.c) res_send: created socket %d\n", res_sock)); #endif if (__connect(res_sock, (struct sockaddr *)&host, sizeof(struct sockaddr), libPtr) < 0) { #if defined(__AROS__) D(bug("[AROSTCP](res_send.c) res_send: Failed to connect\n")); #endif terrno = readErrnoValue(libPtr); #ifdef RES_DEBUG Perror("connect (vc)"); #endif /* RES_DEBUG */ (void) __CloseSocket(res_sock, libPtr); res_sock = -1; continue; } } /* * Send length & message */ len = htons((u_short)buflen); if ((__send(res_sock, (char *)&len, sizeof(len), 0, libPtr) != sizeof(len)) || ((__send(res_sock, (char *)buf, buflen, 0, libPtr) != buflen))) { #if defined(__AROS__) D(bug("[AROSTCP](res_send.c) res_send: Failed sending query\n")); #endif terrno = readErrnoValue(libPtr); #ifdef RES_DEBUG Perror("write(vc)"); #endif /* RES_DEBUG */ (void) __CloseSocket(res_sock, libPtr); res_sock = -1; continue; } /* * Receive length & response */ cp = answer; len = sizeof(short); while (len != 0 && (n = __recv(res_sock, (char *)cp, (int)len, 0, libPtr)) > 0) { cp += n; len -= n; } if (n <= 0) { terrno = readErrnoValue(libPtr); #if defined(__AROS__) D(bug("[AROSTCP](res_send.c) res_send: Failed recieving response\n")); #endif #ifdef RES_DEBUG Perror("read (vc)"); #endif /* RES_DEBUG */ (void) __CloseSocket(res_sock, libPtr); res_sock = -1; /* * A long running process might get its TCP * connection reset if the remote server was * restarted. Requery the server instead of * trying a new one. When there is only one * server, this means that a query might work * instead of failing. We only allow one reset * per query to prevent looping. */ if (terrno == ECONNRESET && !connreset) { connreset = 1; ns--; } continue; } cp = answer; if ((resplen = ntohs(*(u_short *)cp)) > anslen) { #if defined(__AROS__) D(bug("[AROSTCP](res_send.c) res_send: Truncated response\n")); #endif #ifdef RES_DEBUG Printf("response truncated\n"); #endif /* RES_DEBUG */ len = anslen; truncated = 1; } else len = resplen; while (len != 0 && (n = __recv(res_sock, (char *)cp, (int)len, 0, libPtr)) > 0) { cp += n; len -= n; } if (n <= 0) { #if defined(__AROS__) D(bug("[AROSTCP](res_send.c) res_send: Error recieving response\n")); #endif terrno = readErrnoValue(libPtr); #ifdef RES_DEBUG Perror("read (vc)"); #endif /* RES_DEBUG */ (void) __CloseSocket(res_sock, libPtr); res_sock = -1; continue; } if (truncated) { /* * Flush rest of answer * so connection stays in synch. */ anhp->tc = 1; len = resplen - anslen; while (len != 0) { n = (len > JUNK_SIZE ? JUNK_SIZE : len); if ((n = __recv(res_sock, junk, n, 0, libPtr)) > 0) len -= n; else break; } } } else { #if defined(__AROS__) D(bug("[AROSTCP](res_send.c) res_send: Using datagrams\n")); #endif /* * Use datagrams. */ if (res_sock < 0) { res_sock = __socket(AF_INET, SOCK_DGRAM, 0, libPtr); if (res_sock < 0) { #if defined(__AROS__) D(bug("[AROSTCP](res_send.c) res_send: Failed to create socket\n")); #endif terrno = readErrnoValue(libPtr); #ifdef RES_DEBUG Perror("socket (dg)"); #endif /* RES_DEBUG */ continue; } } /* * I'm tired of answering this question, so: * On a 4.3BSD+ machine (client and server, * actually), sending to a nameserver datagram * port with no nameserver will cause an * ICMP port unreachable message to be returned. * If our datagram socket is "connected" to the * server, we get an ECONNREFUSED error on the next * socket operation, and select returns if the * error message is received. We can thus detect * the absence of a nameserver without timing out. * If we have sent queries to at least two servers, * however, we don't want to remain connected, * as we wish to receive answers from the first * server to respond. */ #warning "TODO*: see comment here .." /* This piece of code still behaves slightly wrong in case of ECONNREFUSED error. On next retry socket will be in disconnected state and instead of getting ECONNREFUSED again we'll timeout in WaitSelect() and get ETIMEDOUT. However, this is not critical and is queued for future - Pavel Fedin*/ if (try == 0 && nscount == 1) { /* * Don't use connect if we might * still receive a response * from another server. */ if (connected == 0) { if (__connect(res_sock, (struct sockaddr *)&host, sizeof(struct sockaddr), libPtr) < 0) { #if defined(__AROS__) D(bug("[AROSTCP](res_send.c) res_send: Error connecting\n")); #endif #ifdef RES_DEBUG Perror("connect (dg)"); #endif /* RES_DEBUG */ continue; } connected = 1; } if (__send(res_sock, buf, buflen, 0, libPtr) != buflen) { #if defined(__AROS__) D(bug("[AROSTCP](res_send.c) res_send: Error sending\n")); #endif #ifdef RES_DEBUG Perror("send (dg)"); #endif /* RES_DEBUG */ continue; } } else { /* * Disconnect if we want to listen * for responses from more than one server. */ if (connected) { (void) __connect(res_sock, &no_addr, sizeof(no_addr), libPtr); connected = 0; } if (__sendto(res_sock, buf, buflen, 0, (struct sockaddr *)&host, sizeof(struct sockaddr), libPtr) != buflen) { #if defined(__AROS__) D(bug("[AROSTCP](res_send.c) res_send: [__sendto] Error\n")); #endif #ifdef RES_DEBUG Perror("sendto (dg)"); #endif /* RES_DEBUG */ continue; } } /* * Wait for reply */ timeout.tv_sec = (_res.retrans << try); if (try > 0) timeout.tv_sec /= nscount; if (timeout.tv_sec <= 0) timeout.tv_sec = 1; timeout.tv_usec = 0; wait: FD_ZERO(&dsmask); FD_SET(res_sock, &dsmask); n = __WaitSelect(res_sock+1, &dsmask, NULL, NULL, &timeout, NULL, libPtr); if (n < 0) { #if defined(__AROS__) D(bug("[AROSTCP](res_send.c) res_send: [__WaitSelect] Error\n")); #endif #ifdef RES_DEBUG Perror("select"); #endif /* RES_DEBUG */ terrno = readErrnoValue(libPtr); if (terrno == EINTR) { #if defined(__AROS__) D(bug("[AROSTCP](res_send.c) res_send: closing socket\n")); #endif __CloseSocket(res_sock, libPtr); res_sock = -1; return (-1); } continue; } if (n == 0) { /* * timeout */ #if defined(__AROS__) D(bug("[AROSTCP](res_send.c) res_send: Timeout!\n")); #endif #ifdef RES_DEBUG Printf("timeout\n"); #endif /* RES_DEBUG */ #if 1 || BSD >= 43 gotsomewhere = 1; #endif continue; } if ((resplen = __recv(res_sock, answer, anslen, 0, libPtr)) <= 0) { #if defined(__AROS__) D(bug("[AROSTCP](res_send.c) res_send: Error recieving\n")); #endif #ifdef RES_DEBUG Perror("recv (dg)"); #endif /* RES_DEBUG */ continue; } gotsomewhere = 1; if (id != anhp->id) { /* * response from old query, ignore it */ #ifdef RES_DEBUG Printf("old answer:\n"); __p_query(answer, libPtr); #endif /* RES_DEBUG */ goto wait; } if (!(_res.options & RES_IGNTC) && anhp->tc) { /* * get rest of answer; * use TCP with same server. */ #if defined(__AROS__) D(bug("[AROSTCP](res_send.c) res_send: Response is truncated\n")); #endif #ifdef RES_DEBUG Printf("truncated answer\n"); #endif /* RES_DEBUG */ (void)__CloseSocket(res_sock, libPtr); res_sock = -1; v_circuit = 1; goto usevc; } } #if defined(__AROS__) D(bug("[AROSTCP](res_send.c) res_send: Recieved answer\n")); #endif #ifdef RES_DEBUG Printf("got answer:\n"); __p_query(answer, libPtr); #endif /* RES_DEBUG */ /* * If using virtual circuits, we assume that the first server * is preferred * over the rest (i.e. it is on the local * machine) and only keep that one open. * If we have temporarily opened a virtual circuit, * or if we haven't been asked to keep a socket open, * close the socket. */ if ((v_circuit && ((_res.options & RES_USEVC) == 0 || ns->s_addr != 0)) || (_res.options & RES_STAYOPEN) == 0) { #if defined(__AROS__) D(bug("[AROSTCP](res_send.c) res_send: Closing socket\n")); #endif (void) __CloseSocket(res_sock, libPtr); res_sock = -1; } return (resplen); }