/*! * Request a new ID that is not currently in use. * * @return Returns an ID in the range [1, MaxID] or 0 if there are no * unused IDs. */ FUND::UINT32 GetID() { EXPONENTIAL_BACKOFF<STATS> backoff(1, _stats); for (FUND::UINT32 i = 0; i < _numElements; i++) { FUND::UINT32 val = OPS::Load(&_bits[i]); while (val != 0xffffffff) { FUND::UINT32 bit = 0; for (FUND::UINT32 tval = val; tval & 1; tval >>= 1) bit++; FUND::UINT32 newval = val | (1 << bit); if (OPS::CompareAndDidSwap(&_bits[i], val, newval)) return i*sizeof(FUND::UINT32) + bit + 1; backoff.Delay(); val = OPS::Load(&_bits[i]); } } return 0; }
bool SessionImpl::nextReceiver(qpid::messaging::Receiver& receiver, qpid::messaging::Duration timeout) { while (true) { txError.raise(); try { std::string destination; if (incoming.getNextDestination(destination, adjust(timeout))) { qpid::sys::Mutex::ScopedLock l(lock); Receivers::const_iterator i = receivers.find(destination); if (i == receivers.end()) { throw qpid::messaging::ReceiverError(QPID_MSG("Received message for unknown destination " << destination)); } else { receiver = i->second; } return true; } else { return false; } } catch (TransportFailure&) { reconnect(); } catch (const qpid::framing::ResourceLimitExceededException& e) { if (backoff()) return false; else throw qpid::messaging::TargetCapacityExceeded(e.what()); } catch (const qpid::SessionException& e) { rethrow(e); } catch (const qpid::ClosedException&) { throw qpid::messaging::SessionClosed(); } catch (const qpid::ConnectionException& e) { throw qpid::messaging::ConnectionError(e.what()); } catch (const qpid::ChannelException& e) { throw qpid::messaging::MessagingException(e.what()); } } }
/*! * Pop an element off the head of the lifo queue. * * @param[out] isEmpty If Pop() returns NULL and \a isEmpty is not NULL, the * \a isEmpty parameter is set to TRUE. This parameter * is not particularly useful, but it is provided for * symetry with LIFO_PTR::Pop(). * @param[in] maxRetries This parameter is ignored, but it is provided for * symetry with LIFO_PTR::Pop(). * * @return Returns the popped element on success, or NULL if the queue is empty. */ ELEMENT *Pop(bool *isEmpty=0, unsigned maxRetries=0) { HEAD oldHead; HEAD newHead; ELEMENT *element; EXPONENTIAL_BACKOFF<STATS> backoff(1, _stats); do { backoff.Delay(); oldHead._word = OPS::Load(&_head._word); if (oldHead._fields._iElement == 0) { if (isEmpty) *isEmpty = true; return 0; } element = _heap->Pointer(oldHead._fields._iElement); newHead._fields._iElement = _heap->Index(element->_next); newHead._fields._counter = oldHead._fields._counter+1; } while (!OPS::CompareAndDidSwap(&_head._word, oldHead._word, newHead._word, BARRIER_CS_NEXT)); // BARRIER_CS_NEXT above ensures that all processors see that the element is removed from // the queue before the consumer uses the element. return element; }
EndPoint::EndPoint(const char *const name, const char *const location, const Parameters /*params*/) : mName(name), mLocation(location), mContext(0), mNameMap(), mMessageFactory(), mNetworkThread(), mRunning(false), mStarted(false), mNetworkLock(), mConnectQueue(), mSendQueue() { THERON_ASSERT_MSG(!mName.IsNull(), "Must supply a unique, non-null name for each endpoint"); THERON_ASSERT_MSG(!mLocation.IsNull(), "Must supply a valid port address for each endpoint"); // Initialize the per-process context. mContext = InitializeContext(); // Don't start the network thread if networking isn't enabled. if (mContext->Enabled()) { // Start the network thread. mRunning = true; mNetworkThread.Start(NetworkThreadEntryPoint, this); // Wait for the network thread to start. uint32_t backoff(0); while (!mStarted) { Detail::Utils::Backoff(backoff); } } }
SCORE LanguageModel::BackoffScore( const std::vector<const Factor*> &context) const { //cerr << "backoff="; //DebugContext(context); SCORE ret; size_t stoppedAtInd; const Node<const Factor*, LMScores> &node = m_root.getNode(context, stoppedAtInd); if (stoppedAtInd == context.size()) { // found entire ngram ret = node.getValue().backoff; } else { if (stoppedAtInd == 0) { ret = m_oov; stoppedAtInd = 1; } else { ret = node.getValue().backoff; } // recursive std::vector<const Factor*> backoff(context.begin() + stoppedAtInd, context.end()); ret += BackoffScore(backoff); } return ret; }
/*** Slowpath TATAS acquire. This performs exponential backoff */ inline int tatas_acquire_slowpath(tatas_lock_t* lock) { int b = 64; do { backoff(&b); } while (tas(lock)); return b; }
inline void write_lock() { // set WRITE flag BaseType oldV = value.load(); for (;;) { if ((oldV & FLAG_WRITE) != 0) { backoff(BackoffWrite); oldV = value.load(); } else if (value.compare_exchange_weak(oldV, oldV | FLAG_WRITE)) break; } // wait until there are no more readers while (value.load() != FLAG_WRITE) backoff(BackoffRead); assert(value.load() == FLAG_WRITE); }
void stpcDeferredDelete(stpcProxy *proxy, void (*freeData)(void *), void *data, void (*backoff)(int)) { stpcNode *node; int n = 0; while ((node = _newNode(proxy, true)) == NULL) { backoff(n++); } node->freeData = freeData; node->data = data; _queueNode(proxy, node); }
inline void read_lock() { BaseType oldV = value.load(); for (;;) { if ((oldV & FLAG_WRITE) != 0) { backoff(BackoffWrite); oldV = value.load(); } else if (value.compare_exchange_weak(oldV, oldV+1)) break; } BaseType v = value.load(); if (v == 0) fail(v, "Must be positive"); if (v == FLAG_WRITE) fail(v, "Write Flag must not be set"); }
/* static */ int DicNodeUtils::getBigramNodeProbability(const uint8_t *const dicRoot, const DicNode *const node, MultiBigramMap *multiBigramMap) { const int unigramProbability = node->getProbability(); const int wordPos = node->getPos(); const int prevWordPos = node->getPrevWordPos(); if (NOT_VALID_WORD == wordPos || NOT_VALID_WORD == prevWordPos) { // Note: Normally wordPos comes from the dictionary and should never equal NOT_VALID_WORD. return backoff(unigramProbability); } if (multiBigramMap) { return multiBigramMap->getBigramProbability( dicRoot, prevWordPos, wordPos, unigramProbability); } return BinaryFormat::getBigramProbability(dicRoot, prevWordPos, wordPos, unigramProbability); }
/* * Attempt to add a new element at the given location. Return TRUE if it could * be added there, FALSE if not. */ bool AddAt(FUND::UINT32 index, KEY key, const OBJECT &userObj) { // If this location is available, mark it as reserved. // // The BARRIER_CS_NEXT here works in conjunction with the other barrier marked (B). // This ensures that the read of _map[index] is made before the read of // _highWaterMark below. Otherwise, we might read a stale version of _highWaterMark // and not realize that _highWaterMark needs to be updated for this new element. // (See reference mark (C) below.) // if (!OPS::CompareAndDidSwap(&_map[index], KeyAvailable, KeyReserved, BARRIER_CS_NEXT)) return false; // Now that the position is reserved, we can safely write to it without // anyone else using it. // // The BARRIER_ST_PREV here works in conjunction with the other barrier marked (A). // They ensure that the write of _object[index] is visible on other processors // by the time the _map[index] is made valid. // _objects[index] = userObj; OPS::Store(&_map[index], key, BARRIER_ST_PREV); // Make sure the high water mark stays above all the valid entries. // If we're storing at the free location hint, we just bump the hint, // assuming that the next location is more likely to be free than this // one. // FUND::UINT32 highWater; EXPONENTIAL_BACKOFF<STATS> backoff(1, _stats); do { backoff.Delay(); // Reference mark (C). This is the read of _highWaterMark that is synchronized // with barrier (B). If this read were to happen before the CompareAndDidSwap on // _map[index] above, we might get a stale value of _highWaterMark. This is // prevented by barrier (B). // highWater = OPS::Load(&_highWaterMark); if (index < highWater) break; } while (!OPS::CompareAndDidSwap(&_highWaterMark, highWater, index+1)); OPS::CompareAndSwap(&_freeLocationHint, index, index+1); return true; }
/*! * Release an ID, making it available for reuse. * * @param[in] id The ID, which must be in the range [1,MaxID]. */ void ReleaseID(FUND::UINT32 id) { id--; FUND::UINT32 i = id >> 5; FUND::UINT32 bit = 1 << (id & 0x1f); FUND::UINT32 val; FUND::UINT32 newval; EXPONENTIAL_BACKOFF<STATS> backoff(1, _stats); do { backoff.Delay(); val = OPS::Load(&_bits[i]); newval = val & ~bit; } while (!OPS::CompareAndDidSwap(&_bits[i], val, newval)); }
static void check_connected( void *user_data ) { UNUSED( user_data ); debug( "Checking a connection ( fd = %d, ip = %#x, port = %u ).", connection.fd, connection.ip, connection.port ); assert( secure_channel_initialized ); assert( connection.fd >= 0 ); set_writable( connection.fd, false ); delete_fd_handler( connection.fd ); int err = 0; socklen_t length = sizeof( error ); int ret = getsockopt( connection.fd, SOL_SOCKET, SO_ERROR, &err, &length ); if ( ret < 0 ) { error( "Failed to retrieve error code ( fd = %d, ret = %d, errno = %s [%d] ).", connection.fd, ret, strerror( errno ), errno ); return; } switch ( err ) { case 0: connected(); break; case EINTR: case EAGAIN: case ECONNREFUSED: case ENETUNREACH: case ETIMEDOUT: warn( "Failed to connect ( fd = %d, errno = %s [%d] ).", connection.fd, strerror( err ), err ); backoff(); return; case EINPROGRESS: set_fd_handler( connection.fd, NULL, NULL, ( event_fd_callback ) check_connected, NULL ); set_writable( connection.fd, true ); break; default: error( "Failed to connect ( fd = %d, errno = %s [%d] ).", connection.fd, strerror( err ), err ); clear_connection(); return; } }
/*! * Push a list of elements onto the head of the lifo queue. * * @param[in] listHead A list of ELEMENTs linked through their _next pointers. The * last element's _next pointer must be NULL. * @param[in] listTail The last element in the list. */ void PushList(ELEMENT *listHead, ELEMENT *listTail) { HEAD oldHead; HEAD newHead; EXPONENTIAL_BACKOFF<STATS> backoff(1, _stats); do { backoff.Delay(); oldHead._word = OPS::Load(&_head._word); listTail->_next = _heap->Pointer(oldHead._fields._iElement); newHead._fields._iElement = _heap->Index(listHead); newHead._fields._counter = oldHead._fields._counter+1; // BARRIER_CS_PREV below ensures that all processors will see the write to _next // before the element is inserted into the queue. } while (!OPS::CompareAndDidSwap(&_head._word, oldHead._word, newHead._word, BARRIER_CS_PREV)); }
// request permission to abort enemy tx. For now, policies are totally // local, so we don't need a parameter to this method ConflictResolutions onConflict() { if (policy == POLITE) { if (tries > MAX_BACKOFF_RETRIES) return AbortOther; backoff(); return Wait; } else if (policy == PATIENT) { return Wait; } else if (policy == AGGRESSIVE) { return AbortOther; } else if (policy == TIMID) { return AbortSelf; } return Wait; }
/*! * Atomically clears the lifo queue and returns a pointer to the previous contents. * * @return Returns a pointer to a linked list with the previous elements in * in the queue, or NULL if the queue was already empty. */ ELEMENT *Clear() { HEAD oldHead; HEAD newHead; EXPONENTIAL_BACKOFF<STATS> backoff(1, _stats); newHead._fields._iElement = 0; do { backoff.Delay(); oldHead._word = OPS::Load(&_head._word); newHead._fields._counter = oldHead._fields._counter+1; } while (!OPS::CompareAndDidSwap(&_head._word, oldHead._word, newHead._word, BARRIER_CS_NEXT)); // BARRIER_CS_NEXT above ensures that all processors see that the elements are // removed from the list before the caller starts changing them. return _heap->Pointer(oldHead._fields._iElement); }
void run() { int maxSleepTimeMillis = 1000; Backoff backoff( maxSleepTimeMillis, maxSleepTimeMillis * 2 ); // Double previous sleep duration ASSERT_EQUALS( backoff.getNextSleepMillis( 0, 0, 0 ), 1 ); ASSERT_EQUALS( backoff.getNextSleepMillis( 2, 0, 0 ), 4 ); ASSERT_EQUALS( backoff.getNextSleepMillis( 256, 0, 0 ), 512 ); // Make sure our backoff increases to the maximum value ASSERT_EQUALS( backoff.getNextSleepMillis( maxSleepTimeMillis - 200, 0, 0 ), maxSleepTimeMillis ); ASSERT_EQUALS( backoff.getNextSleepMillis( maxSleepTimeMillis * 2, 0, 0 ), maxSleepTimeMillis ); // Make sure that our backoff gets reset if we wait much longer than the maximum wait unsigned long long resetAfterMillis = maxSleepTimeMillis + maxSleepTimeMillis * 2; ASSERT_EQUALS( backoff.getNextSleepMillis( 20, resetAfterMillis, 0), 40 ); // no reset here ASSERT_EQUALS( backoff.getNextSleepMillis( 20, resetAfterMillis + 1, 0), 1 ); // reset expected }
int lumberjack_ensure_connected(struct lumberjack *lumberjack) { int rc; struct backoff sleeper; backoff_init(&sleeper, &MIN_SLEEP, &MAX_SLEEP); while (!lumberjack_connected(lumberjack)) { backoff(&sleeper); rc = lumberjack_connect(lumberjack); if (rc != 0) { flog(stdout, "Connection attempt to %s:%hd failed: %s", lumberjack->host, lumberjack->port, strerror(errno)); } else { /* we're connected! */ backoff_clear(&sleeper); } } insist(lumberjack->fd > 0, "lumberjack->fd must be > 0 after a connect, was %d", lumberjack->fd); insist(lumberjack->ssl != NULL, "lumberjack->ssl must not be NULL after a connect"); return 0; } /* lumberjack_connect_block */
int main(int argc, char *argv[]) { int retc = 0; int ret; char *hostfile = NULL; char *cachefile = NULL; char *xml = NULL; char *xmlfile = NULL; int cachefd = -1; char value[64]; char units[64]; int retry_count = 0, ret2; if (get_config(argc, argv) < 0) { retc = 2; goto cleanup; } if (config.heartbeat > 0) { debug("Checking heartbeat for %s with threshold %d\n", config.host, config.heartbeat); } else { debug("Checking %s for %s metric\n", config.host, config.metric); } hostfile = get_full_cache_path(config.cachepath, config.host); cachefile = get_full_cache_path(config.cachepath, config.cachename); retry: debug("Checking cache at %s\n", cachefile); ret = check_cache_age(cachefile); if (ret < 0) { printf("ERROR: Unable to check cache age.\n"); retc = 2; goto cleanup; } if (ret < config.max_age) { debug("Cache age is %d\n", ret); } else { debug("Cache age greater than configured max (%d >= %d)\n", ret, config.max_age); debug("Connecting to %s on port %d\n", config.gmetad_host, config.gmetad_port); ret = fetch_xml(config.gmetad_host, config.gmetad_port, &xml); if (ret < 0) { printf("ERROR: Unable to get XML data: %d.\n", ret); retc = 2; goto cleanup; } debug("Read %d bytes from %s\n", ret, config.gmetad_host); if (config.dump) { xmlfile = calloc((strlen(config.cachepath) + 9), sizeof(char)); sprintf(xmlfile, "%s/dump.xml", config.cachepath); debug("Dumping XML to %s\n", xmlfile); if (write_xml(xml, ret, xmlfile) < 0) { printf("ERROR: Unable to dump XML.\n"); retc = 2; goto cleanup; } } ret2 = get_cache_lock(cachefile, &cachefd); if (ret2 < 0) { if (retry_count == MAX_RETRY) { printf("ERROR: Unable to get cache lock after retrying %d times. Stale lock?", retry_count); retc = 2; goto cleanup; } else { backoff(retry_count / 2.0); } retry_count++; goto retry; } debug("Parsing XML into %s\n", config.cachepath); ret = parse_xml_to_cache(xml, ret, config.cachepath, cachefile); if (ret < 0) { printf("ERROR: Unable to parse XML.\n"); retc = 2; goto cleanup; } touch_cache_lock(cachefile); release_cache_lock(cachefile, &cachefd); } if (config.heartbeat > 0) { strcpy(config.metric, "#REPORTED"); } if (locate_hostfile(hostfile) < 0) { printf("CRITICAL - Unable to locate cache file for %s\n", config.host); retc = 2; goto cleanup; } debug("Fetching %s metric from cache at %s\n", config.metric, hostfile); ret = fetch_value_from_cache(hostfile, config.metric, value, units); if (ret < 0) { printf("CRITICAL - Unable to read cache at %s\n", hostfile); retc = 2; goto cleanup; } else if (ret == 0) { printf("CRITICAL - Metric %s not found\n", config.metric); retc = 2; goto cleanup; } debug("Checking...\n"); if (config.heartbeat > 0) { int diff = time(NULL) - strtol(value, NULL, 10); if (diff > config.heartbeat) { printf("CRITICAL - %d over threshold %d\n", diff, config.heartbeat); retc = 2; goto cleanup; } else { printf("OK - %d\n", diff); goto cleanup; } } if (threshold_check(config.critical, value)) { printf("CRITICAL - %s %s\n", value, units); retc = 2; } else { if (threshold_check(config.warning, value)) { printf("WARNING - %s %s\n", value, units); retc = 1; } else { printf("OK - %s %s\n", value, units); } } cleanup: if (cachefd >= 0) { release_cache_lock(cachefile, &cachefd); } if (xml != NULL) free(xml); if (xmlfile != NULL) free(xmlfile); if (hostfile != NULL) free(hostfile); if (cachefile != NULL) free(cachefile); exit(retc); }
void *emitter(void *arg) { int rc; struct emitter_config *config = arg; insist(config->zmq != NULL, "zmq is NULL"); insist(config->zmq_endpoint != NULL, "zmq_endpoint is NULL"); insist(config->ssl_ca_path != NULL, "ssl_ca_path is NULL"); insist(config->window_size > 0, "window_size (%d) must be positive", (int)config->window_size); insist(config->host != NULL, "host is NULL"); insist(config->port > 0, "port (%hd) must be positive", config->port); void *socket = zmq_socket(config->zmq, ZMQ_PULL); insist(socket != NULL, "zmq_socket() failed: %s", strerror(errno)); int64_t hwm = 100; //zmq_setsockopt(socket, ZMQ_HWM, &hwm, sizeof(hwm)); zmq_compat_set_recvhwm(socket, hwm); rc = zmq_bind(socket, config->zmq_endpoint); insist(rc != -1, "zmq_bind(%s) failed: %s", config->zmq_endpoint, zmq_strerror(errno)); struct timespec start; clock_gettime(CLOCK_MONOTONIC, &start); //long count = 0; struct backoff sleeper; backoff_init(&sleeper, &MIN_SLEEP, &MAX_SLEEP); struct lumberjack *lumberjack; lumberjack = lumberjack_new(config->host, config->port, config->window_size); insist(lumberjack != NULL, "lumberjack_new failed"); lumberjack->ring_size = config->window_size; if (config->ssl_ca_path != NULL) { rc = lumberjack_set_ssl_ca(lumberjack, config->ssl_ca_path); insist(rc == 0, "lumberjack_set_ssl_ca failed, is '%s' a valid ssl cert?", config->ssl_ca_path); } long count = 0; long bytes = 0; zmq_pollitem_t items[1]; items[0].socket = socket; items[0].events = ZMQ_POLLIN; int can_flush = 0; for (;;) { /* Receive an event from a harvester and put it in the queue */ zmq_msg_t message; rc = zmq_msg_init(&message); insist(rc == 0, "zmq_msg_init failed"); rc = zmq_poll(items, 1, 1000000 /* microseconds */); if (rc == 0) { /* poll timeout. We're idle, so let's flush and back-off. */ if (can_flush) { /* only flush if there's something to flush... */ flog(stdout, "flushing since nothing came in over zmq"); /* We flush here to keep slow feeders closer to real-time */ rc = lumberjack_flush(lumberjack); can_flush = 0; if (rc != 0) { /* write failure, reconnect (which will resend) and such */ lumberjack_disconnect(lumberjack); lumberjack_ensure_connected(lumberjack); } } backoff(&sleeper); /* Restart the loop - checking to see if there's any messages */ continue; } /* poll successful, read a message */ //rc = zmq_recv(socket, &message, 0); rc = zmq_compat_recvmsg(socket, &message, 0); insist(rc == 0 /*|| errno == EAGAIN */, "zmq_recv(%s) failed (returned %d): %s", config->zmq_endpoint, rc, zmq_strerror(errno)); /* Clear the backoff timer since we received a message successfully */ backoff_clear(&sleeper); /* Write the data over lumberjack. This will handle any * connection/reconnection/ack issues */ lumberjack_send_data(lumberjack, zmq_msg_data(&message), zmq_msg_size(&message)); /* Since we sent data, let it be known that we can flush if idle */ can_flush = 1; /* Stats for debugging */ count++; bytes += zmq_msg_size(&message); zmq_msg_close(&message); if (count == 10000) { struct timespec now; clock_gettime(CLOCK_MONOTONIC, &now); double s = (start.tv_sec + 0.0) + (start.tv_nsec / 1000000000.0); double n = (now.tv_sec + 0.0) + (now.tv_nsec / 1000000000.0); flog(stdout, "Rate: %f (bytes: %f)\n", (count + 0.0) / (n - s), (bytes + 0.0) / (n - s)); struct rusage rusage; rc = getrusage(RUSAGE_SELF, &rusage); insist(rc == 0, "getrusage failed: %s\n", strerror(errno)); flog(stdout, "cpu user/system: %d.%06d / %d.%06d\n", (int)rusage.ru_utime.tv_sec, (int)rusage.ru_utime.tv_usec, (int)rusage.ru_stime.tv_sec, (int)rusage.ru_stime.tv_usec); clock_gettime(CLOCK_MONOTONIC, &start); bytes = 0; count = 0; } } /* forever */ } /* emitter */
int main(int argc, char** argv) { signal(SIGINT, signalHandler); signal(SIGTERM, signalHandler); int s = -1; int success = 0; SSL* tls = NULL; /* * Parse and validate args */ if (parseArgs(argc, argv)) { usage(argv[0]); return 1; } // make logs a little easier to read/more useful setvbuf(stderr, NULL, _IOLBF, 0); if (broadcast) { timestamp_f(stderr); fprintf(stderr, "broadcast environment: %s\n", (production ? "prod" : "dev")); } else if (noSend == 0) { timestamp_f(stderr); fprintf(stderr, "device token: %s\n", deviceToken); } else { timestamp_f(stderr); fprintf(stderr, "build and report only; no send\n"); } timestamp_f(stderr); fprintf(stderr, "cert. file: %s. passphrase loaded\n", certPath); timestamp_f(stderr); fprintf(stderr, "database path: %s\n", databasePath); timestamp_f(stderr); fprintf(stderr, "message: \"%s\"\n", message); timestamp_f(stderr); fprintf(stderr, "host: %s, port: %d\n", host, port); timestamp_f(stderr); fprintf(stderr, "url: %s\n", url); timestamp_f(stderr); fprintf(stderr, "wotd: %d\n", wotd); time_t expiration = time(NULL) + 43200; void* notificationPayload = NULL; size_t notificationPayloadSize = 0; if (buildNotificationPayload(wotd, broadcast, production, deviceToken, databasePath, message, url, wotdExpiration, expiration, ¬ificationPayload, ¬ificationPayloadSize)) { timestamp_f(stderr); fprintf(stderr, "failed to build notification payload\n"); return -1; } timestamp_f(stderr); fprintf(stderr, "notification length is %ld\n", notificationPayloadSize); if (noSend) { free(notificationPayload); return 0; } /* * Connect to server */ int nb = 0; int b = 0; while (!success && !_shutdown && time(NULL) < expiration) { while (!_shutdown && time(NULL) < expiration && s < 0) { timestamp_f(stderr); fprintf(stderr, "attempting connection to %s:%d\n", host, port); s = socketConnect(host, port); if (s < 0) { timestamp_f(stderr); fprintf(stderr, "connection to %s:%d failed\n", host, port); b = backoff(); if (_shutdown || time(NULL) + b >= expiration) { free(notificationPayload); return 1; } timestamp_f(stderr); fprintf(stderr, "will try again in %d s\n", b); sleep(b); continue; } timestamp_f(stderr); fprintf(stderr, "successfully connected to %s:%d\n", host, port); } if (_shutdown || time(NULL) >= expiration) { free(notificationPayload); if (s >= 0) close(s); return 1; } tls = makeTlsConnection(s, certPath, passphrase, cacertPath); if (!tls) { timestamp_f(stderr); fprintf(stderr, "TLS handshake failed\n"); close(s); s = -1; b = backoff(); if (_shutdown || time(NULL) + b >= expiration) { free(notificationPayload); return 1; } timestamp_f(stderr); fprintf(stderr, "will reconnect in %d s\n", b); sleep(b); continue; } if (_shutdown) { free(notificationPayload); stopTlsConnection(tls); return 1; } nb = SSL_write(tls, notificationPayload, notificationPayloadSize); if (nb != notificationPayloadSize) { timestamp_f(stderr); fprintf(stderr, "SSL_write: %s", ERR_error_string(nb, NULL)); stopTlsConnection(tls); s = -1; tls = NULL; b = backoff(); if (_shutdown || time(NULL) + b >= expiration) { free(notificationPayload); return 1; } timestamp_f(stderr); fprintf(stderr, "will reconnect in %d s\n", b); sleep(b); continue; } timestamp_f(stderr); fprintf(stderr, "successfully wrote %d bytes\n", nb); free(notificationPayload); success = 1; } if (_shutdown || time(NULL) >= expiration) { if (tls) stopTlsConnection(tls); else if (s >= 0) close(s); return 1; } /* * Check for error response packet(s) */ timestamp_f(stderr); fprintf(stderr, "checking for error responses (10 s)\n"); char errorResponse[6]; int numErrors; for (numErrors=0; (nb=SSL_read(tls, errorResponse, sizeof(errorResponse))) == sizeof(errorResponse); ++numErrors) { uint32_t identifier; memcpy(&identifier, errorResponse+2, sizeof(identifier)); timestamp_f(stderr); fprintf(stderr, "APNS error response: command %d, status %d, identifier %u (network order)\n", errorResponse[0], errorResponse[1], identifier); } if (nb == 0 || (nb == -1 && errno == EAGAIN)) { if (numErrors == 0) { timestamp_f(stderr); fprintf(stderr, "APNS push successfully sent\n"); } } else if (nb == -1) { timestamp_f(stderr); perror("SSL_read"); } else { timestamp_f(stderr); fprintf(stderr, "SSL_read error %d: %s", nb, ERR_error_string(nb, NULL)); } stopTlsConnection(tls); return 0; }
static bool try_connect() { assert( connection.state != CONNECTED ); int fd = socket( PF_INET, SOCK_STREAM, 0 ); if ( fd < 0 ) { error( "Failed to create a socket ( ret = %d, errno = %s [%d] ).", fd, strerror( errno ), errno ); return false; } int flag = 1; int ret = setsockopt( fd, IPPROTO_TCP, TCP_NODELAY, &flag, sizeof( flag ) ); if ( ret < 0 ) { error( "Failed to set socket options ( fd = %d, ret = %d, errno = %s [%d] ).", fd, ret, strerror( errno ), errno ); return false; } ret = fcntl( fd, F_SETFL, O_NONBLOCK ); if ( ret < 0 ) { error( "Failed to enable non-blocking mode ( fd = %d, ret = %d, errno = %s [%d] ).", fd, ret, strerror( errno ), errno ); close( fd ); return false; } connection.fd = fd; struct sockaddr_in addr; memset( &addr, 0, sizeof( struct sockaddr_in ) ); addr.sin_family = AF_INET; addr.sin_port = htons( connection.port ); addr.sin_addr.s_addr = htonl( connection.ip ); transit_state( CONNECTING ); ret = connect( connection.fd, ( struct sockaddr * ) &addr, sizeof( struct sockaddr_in ) ); if ( ret < 0 ) { switch ( errno ) { case EINTR: case EAGAIN: case ECONNREFUSED: case ENETUNREACH: case ETIMEDOUT: warn( "Failed to connect ( fd = %d, ret = %d, errno = %s [%d] ).", connection.fd, ret, strerror( errno ), errno ); backoff(); return true; case EINPROGRESS: break; default: error( "Failed to connect ( fd = %d, ret = %d, errno = %s [%d] ).", connection.fd, ret, strerror( errno ), errno ); clear_connection(); return false; } } set_fd_handler( connection.fd, NULL, NULL, ( event_fd_callback ) check_connected, NULL ); set_writable( connection.fd, true ); return true; }