void tr_reset(void) { char fname[150]; char fpath[150]; char s[200]; pthread_mutex_lock(&mutex); tr_close(); snprintf(fpath, sizeof(fpath), "%s/%s", USBDISK_PATH, DATA_DIR); snprintf(fname, sizeof(fname), "%s", TR_DATA_FNAME); snprintf(s, sizeof(s), "%s/%s", fpath, fname); unlink(s); snprintf(fpath, sizeof(fpath), "%s/%s", USBDISK_PATH, DATA_DIR); snprintf(fname, sizeof(fname), "%s", TR_HEAD_FNAME); snprintf(s, sizeof(s), "%s/%s", fpath, fname); unlink(s); tr_open(); pthread_mutex_unlock(&mutex); }
/* * run the request */ static HTTPResponse *_runRequest(WOAppReq *app, WOAppHandle woappHandle, WOInstanceHandle instHandle, HTTPRequest *req) { WOConnection *c; HTTPResponse *resp = NULL; int send_status, keepConnection, retryRequest = 0; const char *idString = NULL; WOLog(WO_INFO,"Trying to contact %s:%s on %s(%d)", app->name,app->instance,app->host,app->port); /* Tag the request with a unique identifier (if it hasn't been already) */ /* (It might already have been tagged if we are retrying the request due to refusing new sessions, for example) */ idString = req_HeaderForKey(req, REQUEST_ID_HEADER); if (idString == NULL) { String *requestID = tr_uniqueID(); if (requestID) { req_addHeader(req, REQUEST_ID_HEADER, requestID->text, STR_COPYVALUE); idString = req_HeaderForKey(req, REQUEST_ID_HEADER); str_free(requestID); } } do { c = tr_open(instHandle); /* connect */ if (c == NULL) { WOLog(WO_INFO,"%s:%s NOT LISTENING on %s(%d)", app->name,app->instance,app->host,app->port); app->error = err_connect; return NULL; } /* * app found and is listening on port */ if (app->scheduler->beginTransaction) app->scheduler->beginTransaction(app, instHandle); /* Make sure that we're the only connection header, and we're explicit about the setting */ req_removeHeader(req,CONNECTION); if (c->isPooled) { req_addHeader(req,CONNECTION,HTTP_KEEP_ALIVE,0); } else { req_addHeader(req,CONNECTION,HTTP_CLOSE,0); } WOLog(WO_INFO,"%s:%s on %s(%d) connected [pooled: %s]", app->name, app->instance, app->host, app->port, c->isPooled ? "Yes" : "No"); /* * send the request.... */ send_status = req_sendRequest(req, c->fd); if (send_status != 0) { if ((send_status == TR_RESET) && (retryRequest == 0) && !req->haveReadStreamedData) { /* If we get here the connection was reset. This means the instance has either quit or crashed. */ /* Bump the generation number so all pooled connections to this instance will be invalidated. */ /* Then retry the request with a new connection. If the instance is not running the retry will */ /* fail with a different error and the instance will be marked dead. */ _WOInstance *inst = ac_lockInstance(instHandle); /* note: if we get here, keepConnection == 0 --> this connection will be closed */ if (inst) { ac_cycleInstance(inst, c->generation); ac_unlockInstance(instHandle); } retryRequest++; WOLog(WO_INFO, "retrying request due to connection reset"); /* Must close connection before continuing */ tr_close(c, instHandle, 0); continue; } else { WOLog(WO_ERR,"Failed to send request"); tr_close(c, instHandle, 0); /* close app connection */ if (send_status == -1) app->error = err_read; else app->error = err_send; return NULL; } } /* Note that we have a request queued */ WOLog(WO_INFO,"Request %s sent, awaiting response", req->request_str); /* While the app is processing the request, take the opportunity to check/update the config. */ ac_readConfiguration(); /* * now wait for the response... */ resp = resp_getResponseHeaders(c, instHandle); /* go ahead and read the first chunk of response data */ if (resp && req->method != HTTP_HEAD_METHOD) { if (resp_getResponseContent(resp, 1) == -1) { resp_free(resp); resp = NULL; } } /* Validate the ID */ if (idString && resp) { const char *respID = st_valueFor(resp->headers, REQUEST_ID_HEADER); if (respID != NULL) { if (strcmp(respID, idString) != 0) { WOLog(WO_ERR, "Got response with wrong ID! Dumping response. request ID = %s, response ID = %s", idString, respID); /* note this will cause the connection to be closed below */ resp_free(resp); resp = NULL; } else st_removeKey(resp->headers, REQUEST_ID_HEADER); } else WOLog(WO_WARN, "Got response with no ID."); } app->response = resp; /* * check if this connection can be kept open */ keepConnection = 0; #ifndef CGI /* doesn't make sense to keep the connection for CGI */ if (resp && resp->headers) { const char *keepAlive; keepAlive = st_valueFor(resp->headers, CONNECTION); if (keepAlive) { /* if the keep alive header is set, honor the value */ if (strcasecmp(keepAlive, HTTP_KEEP_ALIVE) == 0) keepConnection = 1; } else { /* no keep alive header - keep alive by default for HTTP/1.1 only */ if (resp->flags & RESP_HTTP11) keepConnection = 1; } } #endif if (resp != NULL) { if (app->scheduler->finalizeTransaction) if (app->scheduler->finalizeTransaction(app, instHandle)) keepConnection = 0; st_removeKey(resp->headers, REFUSING_SESSIONS_HEADER); st_removeKey(resp->headers, LOAD_AVERAGE_HEADER); st_removeKey(resp->headers, CONNECTION); WOLog(WO_INFO,"received ->%d %s",resp->status,resp->statusMsg); retryRequest = 0; } else { if (c != NULL && tr_connectionWasReset(c)) { /* If we get here the connection was reset. This means the instance has either quit or crashed. */ /* Bump the generation number so all pooled connections to this instance will be invalidated. */ /* Then retry the request with a new connection. If the instance is not running the retry will */ /* fail with a different error and the instance will be marked dead. */ /* Note that only one retry due to a connection reset error is allowed. This is to prevent an */ /* infinite loop if the instance dies while processing the request and restarts quickly enough */ /* to process the retry. */ _WOInstance *inst = ac_lockInstance(instHandle); /* note: if we get here, keepConnection == 0 --> this connection will be closed */ if (inst) { ac_cycleInstance(inst, c->generation); ac_unlockInstance(instHandle); } retryRequest++; if (retryRequest == 1) WOLog(WO_INFO, "retrying request due to connection reset"); } else app->error = err_response; } if (resp && resp->content_read < resp->content_length) { resp->keepConnection = keepConnection; resp->instHandle = instHandle; resp->flags |= RESP_CLOSE_CONNECTION; } else { tr_close(c, instHandle, keepConnection); } } while (retryRequest == 1); return resp; }
void rtr_fsm_start(struct rtr_socket *rtr_socket) { rtr_socket->state = RTR_CONNECTING; install_sig_handler(); while(1) { if(rtr_socket->state == RTR_CONNECTING) { RTR_DBG1("State: RTR_CONNECTING"); //old pfx_record could exists in the pfx_table, check if they are too old and must be removed rtr_purge_outdated_records(rtr_socket); if(tr_open(rtr_socket->tr_socket) == TR_ERROR) { rtr_change_socket_state(rtr_socket, RTR_ERROR_TRANSPORT); } else if(rtr_socket->request_session_id) { //change to state RESET, if socket dont has a session_id rtr_change_socket_state(rtr_socket, RTR_RESET); } else { //if we already have a session_id, send a serial query and start to sync if(rtr_send_serial_query(rtr_socket) == RTR_SUCCESS) rtr_change_socket_state(rtr_socket, RTR_SYNC); else rtr_change_socket_state(rtr_socket, RTR_ERROR_FATAL); } } else if(rtr_socket->state == RTR_RESET) { RTR_DBG1("State: RTR_RESET"); if (rtr_send_reset_query(rtr_socket) == 0) { RTR_DBG1("rtr_start: reset pdu sent"); rtr_change_socket_state(rtr_socket, RTR_SYNC); //send reset query after connection established } } else if(rtr_socket->state == RTR_SYNC) { RTR_DBG1("State: RTR_SYNC"); if(rtr_sync(rtr_socket) == 0) rtr_change_socket_state(rtr_socket, RTR_ESTABLISHED); //send reset query after connection established } else if(rtr_socket->state == RTR_ESTABLISHED) { RTR_DBG1("State: RTR_ESTABLISHED"); if(rtr_wait_for_sync(rtr_socket) == RTR_SUCCESS) { //blocks till cache_timeout is expired or PDU was received //serial query senden if(rtr_send_serial_query(rtr_socket) == RTR_SUCCESS) rtr_change_socket_state(rtr_socket, RTR_SYNC); } } else if(rtr_socket->state == RTR_ERROR_NO_DATA_AVAIL) { RTR_DBG1("State: RTR_ERROR_NO_DATA_AVAIL"); rtr_socket->request_session_id = true; rtr_socket->serial_number = 0; rtr_change_socket_state(rtr_socket, RTR_RESET); sleep(ERR_TIMEOUT); rtr_purge_outdated_records(rtr_socket); } else if(rtr_socket->state == RTR_ERROR_NO_INCR_UPDATE_AVAIL) { RTR_DBG1("State: RTR_ERROR_NO_INCR_UPDATE_AVAIL"); rtr_socket->request_session_id = true; rtr_socket->serial_number = 0; rtr_change_socket_state(rtr_socket, RTR_RESET); rtr_purge_outdated_records(rtr_socket); } else if(rtr_socket->state == RTR_ERROR_TRANSPORT) { RTR_DBG1("State: RTR_ERROR_TRANSPORT"); tr_close(rtr_socket->tr_socket); rtr_change_socket_state(rtr_socket, RTR_CONNECTING); sleep(ERR_TIMEOUT); } else if(rtr_socket->state == RTR_ERROR_FATAL) { RTR_DBG1("State: RTR_ERROR_FATAL"); tr_close(rtr_socket->tr_socket); rtr_change_socket_state(rtr_socket, RTR_CONNECTING); sleep(ERR_TIMEOUT); } else if(rtr_socket->state == RTR_SHUTDOWN) { RTR_DBG1("State: RTR_SHUTDOWN"); tr_close(rtr_socket->tr_socket); rtr_socket->request_session_id = true; rtr_socket->serial_number = 0; rtr_socket->last_update = 0; pfx_table_src_remove(rtr_socket->pfx_table, rtr_socket); pthread_exit(NULL); } } }
/* WARNING: This Function has cancelable sections*/ void *rtr_fsm_start(struct rtr_socket *rtr_socket) { if (rtr_socket->state == RTR_SHUTDOWN) return NULL; // We don't care about the old state, but POSIX demands a non null value for setcancelstate int oldcancelstate; pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldcancelstate); rtr_socket->state = RTR_CONNECTING; while(1) { if(rtr_socket->state == RTR_CONNECTING) { RTR_DBG1("State: RTR_CONNECTING"); rtr_socket->has_received_pdus = false; //old pfx_record could exists in the pfx_table, check if they are too old and must be removed //old key_entry could exists in the spki_table, check if they are too old and must be removed rtr_purge_outdated_records(rtr_socket); if(tr_open(rtr_socket->tr_socket) == TR_ERROR) { rtr_change_socket_state(rtr_socket, RTR_ERROR_TRANSPORT); } else if(rtr_socket->request_session_id) { //change to state RESET, if socket dont has a session_id rtr_change_socket_state(rtr_socket, RTR_RESET); } else { //if we already have a session_id, send a serial query and start to sync if(rtr_send_serial_query(rtr_socket) == RTR_SUCCESS) rtr_change_socket_state(rtr_socket, RTR_SYNC); else rtr_change_socket_state(rtr_socket, RTR_ERROR_FATAL); } } else if(rtr_socket->state == RTR_RESET) { RTR_DBG1("State: RTR_RESET"); if (rtr_send_reset_query(rtr_socket) == RTR_SUCCESS) { RTR_DBG1("rtr_start: reset pdu sent"); rtr_change_socket_state(rtr_socket, RTR_SYNC); //start to sync after connection is established } } else if(rtr_socket->state == RTR_SYNC) { RTR_DBG1("State: RTR_SYNC"); if(rtr_sync(rtr_socket) == RTR_SUCCESS) rtr_change_socket_state(rtr_socket, RTR_ESTABLISHED); //wait for next sync after first successful sync } else if(rtr_socket->state == RTR_ESTABLISHED) { RTR_DBG1("State: RTR_ESTABLISHED"); // Allow thread cancellation for recv code path only. // This should be enough since we spend most of the time blocking on recv pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldcancelstate); int ret = rtr_wait_for_sync(rtr_socket); //blocks till expire_interval is expired or PDU was received pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldcancelstate); if(ret == RTR_SUCCESS) { //send serial query if(rtr_send_serial_query(rtr_socket) == RTR_SUCCESS) rtr_change_socket_state(rtr_socket, RTR_SYNC); } } else if(rtr_socket->state == RTR_FAST_RECONNECT){ RTR_DBG1("State: RTR_FAST_RECONNECT"); tr_close(rtr_socket->tr_socket); rtr_change_socket_state(rtr_socket, RTR_CONNECTING); } else if(rtr_socket->state == RTR_ERROR_NO_DATA_AVAIL) { RTR_DBG1("State: RTR_ERROR_NO_DATA_AVAIL"); rtr_socket->request_session_id = true; rtr_socket->serial_number = 0; rtr_change_socket_state(rtr_socket, RTR_RESET); sleep(rtr_socket->retry_interval); rtr_purge_outdated_records(rtr_socket); } else if(rtr_socket->state == RTR_ERROR_NO_INCR_UPDATE_AVAIL) { RTR_DBG1("State: RTR_ERROR_NO_INCR_UPDATE_AVAIL"); rtr_socket->request_session_id = true; rtr_socket->serial_number = 0; rtr_change_socket_state(rtr_socket, RTR_RESET); rtr_purge_outdated_records(rtr_socket); } else if(rtr_socket->state == RTR_ERROR_TRANSPORT) { RTR_DBG1("State: RTR_ERROR_TRANSPORT"); tr_close(rtr_socket->tr_socket); rtr_change_socket_state(rtr_socket, RTR_CONNECTING); RTR_DBG("Waiting %u", rtr_socket->retry_interval); sleep(rtr_socket->retry_interval); } else if(rtr_socket->state == RTR_ERROR_FATAL) { RTR_DBG1("State: RTR_ERROR_FATAL"); tr_close(rtr_socket->tr_socket); rtr_change_socket_state(rtr_socket, RTR_CONNECTING); RTR_DBG("Waiting %u", rtr_socket->retry_interval); sleep(rtr_socket->retry_interval); } else if(rtr_socket->state == RTR_SHUTDOWN) { RTR_DBG1("State: RTR_SHUTDOWN"); pthread_exit(NULL); } } }