static apr_status_t writev_nonblocking(apr_socket_t *s, struct iovec *vec, apr_size_t nvec, apr_bucket_brigade *bb, apr_size_t *cumulative_bytes_written, conn_rec *c) { apr_status_t rv = APR_SUCCESS, arv; apr_size_t bytes_written = 0, bytes_to_write = 0; apr_size_t i, offset; apr_interval_time_t old_timeout; arv = apr_socket_timeout_get(s, &old_timeout); if (arv != APR_SUCCESS) { return arv; } arv = apr_socket_timeout_set(s, 0); if (arv != APR_SUCCESS) { return arv; } for (i = 0; i < nvec; i++) { bytes_to_write += vec[i].iov_len; } offset = 0; while (bytes_written < bytes_to_write) { apr_size_t n = 0; rv = apr_socket_sendv(s, vec + offset, nvec - offset, &n); if (n > 0) { bytes_written += n; for (i = offset; i < nvec; ) { apr_bucket *bucket = APR_BRIGADE_FIRST(bb); if (APR_BUCKET_IS_METADATA(bucket)) { apr_bucket_delete(bucket); } else if (n >= vec[i].iov_len) { apr_bucket_delete(bucket); offset++; n -= vec[i++].iov_len; } else { apr_bucket_split(bucket, n); apr_bucket_delete(bucket); vec[i].iov_len -= n; vec[i].iov_base = (char *) vec[i].iov_base + n; break; } } } if (rv != APR_SUCCESS) { break; } } if ((ap__logio_add_bytes_out != NULL) && (bytes_written > 0)) { ap__logio_add_bytes_out(c, bytes_written); } *cumulative_bytes_written += bytes_written; arv = apr_socket_timeout_set(s, old_timeout); if ((arv != APR_SUCCESS) && (rv == APR_SUCCESS)) { return arv; } else { return rv; } }
void LLPluginProcessParent::idle(void) { bool idle_again; do { // process queued messages mIncomingQueueMutex.lock(); while(!mIncomingQueue.empty()) { LLPluginMessage message = mIncomingQueue.front(); mIncomingQueue.pop(); mIncomingQueueMutex.unlock(); receiveMessage(message); mIncomingQueueMutex.lock(); } mIncomingQueueMutex.unlock(); // Give time to network processing if(mMessagePipe) { // Drain any queued outgoing messages mMessagePipe->pumpOutput(); // Only do input processing here if this instance isn't in a pollset. if(!mPolledInput) { mMessagePipe->pumpInput(); } } if(mState <= STATE_RUNNING) { if(APR_STATUS_IS_EOF(mSocketError)) { // Plugin socket was closed. This covers both normal plugin termination and plugin crashes. errorState(); } else if(mSocketError != APR_SUCCESS) { // The socket is in an error state -- the plugin is gone. LL_WARNS("Plugin") << "Socket hit an error state (" << mSocketError << ")" << LL_ENDL; errorState(); } } // If a state needs to go directly to another state (as a performance enhancement), it can set idle_again to true after calling setState(). // USE THIS CAREFULLY, since it can starve other code. Specifically make sure there's no way to get into a closed cycle and never return. // When in doubt, don't do it. idle_again = false; switch(mState) { case STATE_UNINITIALIZED: break; case STATE_INITIALIZED: { apr_status_t status = APR_SUCCESS; apr_sockaddr_t* addr = NULL; mListenSocket = LLSocket::create(LLSocket::STREAM_TCP); mBoundPort = 0; // This code is based on parts of LLSocket::create() in lliosocket.cpp. status = apr_sockaddr_info_get( &addr, "127.0.0.1", APR_INET, 0, // port 0 = ephemeral ("find me a port") 0, LLAPRRootPool::get()()); if(ll_apr_warn_status(status)) { killSockets(); errorState(); break; } // This allows us to reuse the address on quick down/up. This is unlikely to create problems. ll_apr_warn_status(apr_socket_opt_set(mListenSocket->getSocket(), APR_SO_REUSEADDR, 1)); status = apr_socket_bind(mListenSocket->getSocket(), addr); if(ll_apr_warn_status(status)) { killSockets(); errorState(); break; } // Get the actual port the socket was bound to { apr_sockaddr_t* bound_addr = NULL; if(ll_apr_warn_status(apr_socket_addr_get(&bound_addr, APR_LOCAL, mListenSocket->getSocket()))) { killSockets(); errorState(); break; } mBoundPort = bound_addr->port; if(mBoundPort == 0) { LL_WARNS("Plugin") << "Bound port number unknown, bailing out." << LL_ENDL; killSockets(); errorState(); break; } } LL_DEBUGS("Plugin") << "Bound tcp socket to port: " << addr->port << LL_ENDL; // Make the listen socket non-blocking status = apr_socket_opt_set(mListenSocket->getSocket(), APR_SO_NONBLOCK, 1); if(ll_apr_warn_status(status)) { killSockets(); errorState(); break; } apr_socket_timeout_set(mListenSocket->getSocket(), 0); if(ll_apr_warn_status(status)) { killSockets(); errorState(); break; } // If it's a stream based socket, we need to tell the OS // to keep a queue of incoming connections for ACCEPT. status = apr_socket_listen( mListenSocket->getSocket(), 10); // FIXME: Magic number for queue size if(ll_apr_warn_status(status)) { killSockets(); errorState(); break; } // If we got here, we're listening. setState(STATE_LISTENING); } break; case STATE_LISTENING: { // Launch the plugin process. // Only argument to the launcher is the port number we're listening on std::stringstream stream; stream << mBoundPort; mProcess.addArgument(stream.str()); if(mProcess.launch() != 0) { errorState(); } else { if(mDebug) { // If we're set to debug, start up a gdb instance in a new terminal window and have it attach to the plugin process and continue. std::stringstream cmd; #if LL_DARWIN // The command we're constructing would look like this on the command line: // osascript -e 'tell application "Terminal"' -e 'set win to do script "gdb -pid 12345"' -e 'do script "continue" in win' -e 'end tell' mDebugger.setExecutable("/usr/bin/osascript"); mDebugger.addArgument("-e"); mDebugger.addArgument("tell application \"Terminal\""); mDebugger.addArgument("-e"); cmd << "set win to do script \"gdb -pid " << mProcess.getProcessID() << "\""; mDebugger.addArgument(cmd.str()); mDebugger.addArgument("-e"); mDebugger.addArgument("do script \"continue\" in win"); mDebugger.addArgument("-e"); mDebugger.addArgument("end tell"); mDebugger.launch(); #elif LL_LINUX // The command we're constructing would look like this on the command line: // /usr/bin/xterm -geometry 160x24-0+0 -e '/usr/bin/gdb -n /proc/12345/exe 12345' // This can be changed by setting the following environment variables, for example: // export LL_DEBUG_TERMINAL_COMMAND="/usr/bin/gnome-terminal --geometry=165x24-0+0 -e %s" // export LL_DEBUG_GDB_PATH=/usr/bin/gdb char const* env; std::string const terminal_command = (env = getenv("LL_DEBUG_TERMINAL_COMMAND")) ? env : "/usr/bin/xterm -geometry 160x24+0+0 -e %s"; char const* const gdb_path = (env = getenv("LL_DEBUG_GDB_PATH")) ? env : "/usr/bin/gdb"; cmd << gdb_path << " -n /proc/" << mProcess.getProcessID() << "/exe " << mProcess.getProcessID(); typedef boost::tokenizer< boost::escaped_list_separator< char>, std::basic_string< char>::const_iterator, std::basic_string<char> > tokenizerT; tokenizerT tok(terminal_command.begin(), terminal_command.end(), boost::escaped_list_separator< char >("\\", " ", "'\"")); std::vector< std::basic_string<char> > tokens; for (tokenizerT::iterator cur_token(tok.begin()), end_token(tok.end()); cur_token != end_token; ++cur_token) { if (!cur_token->empty()) tokens.push_back(*cur_token); } std::vector<std::string>::iterator token = tokens.begin(); mDebugger.setExecutable(*token); while (++token != tokens.end()) { if (*token == "%s") { mDebugger.addArgument(cmd.str()); } else { mDebugger.addArgument(*token); } } mDebugger.launch(); #endif } // This will allow us to time out if the process never starts. mHeartbeat.start(); mHeartbeat.setTimerExpirySec(mPluginLaunchTimeout); setState(STATE_LAUNCHED); } } break; case STATE_LAUNCHED: // waiting for the plugin to connect if(pluginLockedUpOrQuit()) { errorState(); } else { // Check for the incoming connection. if(accept()) { // Stop listening on the server port mListenSocket.reset(); setState(STATE_CONNECTED); } } break; case STATE_CONNECTED: // waiting for hello message from the plugin if(pluginLockedUpOrQuit()) { errorState(); } break; case STATE_HELLO: LL_DEBUGS("Plugin") << "received hello message" << LL_ENDL; // Send the message to load the plugin { LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "load_plugin"); message.setValue("file", mPluginFile); sendMessage(message); } setState(STATE_LOADING); break; case STATE_LOADING: // The load_plugin_response message will kick us from here into STATE_RUNNING if(pluginLockedUpOrQuit()) { errorState(); } break; case STATE_RUNNING: if(pluginLockedUpOrQuit()) { errorState(); } break; case STATE_EXITING: if(!mProcess.isRunning()) { setState(STATE_CLEANUP); } else if(pluginLockedUp()) { LL_WARNS("Plugin") << "timeout in exiting state, bailing out" << LL_ENDL; errorState(); } break; case STATE_LAUNCH_FAILURE: if(mOwner != NULL) { mOwner->pluginLaunchFailed(); } setState(STATE_CLEANUP); break; case STATE_ERROR: if(mOwner != NULL) { mOwner->pluginDied(); } setState(STATE_CLEANUP); break; case STATE_CLEANUP: mProcess.kill(); killSockets(); setState(STATE_DONE); break; case STATE_DONE: // just sit here. break; } } while (idle_again); }
static int lisp_handler (request_rec * r) { lisp_cfg_t * cfg = (ap_get_module_config ((r->per_dir_config), (&lisp_module))); int content_length = (-1); int keep_socket_p = 0; apr_socket_t * socket; const char * request_content_length = 0; cfg = local_lisp_cfg(cfg); if ((strcmp ((r->handler), "lisp-handler")) != 0) return (DECLINED); /* Open a connection to the Lisp process. */ ML_LOG_DEBUG (r, "open lisp connection"); CVT_ERROR ((open_lisp_socket (cfg)), "opening connection to Lisp"); (SERVER_SOCKET_SAFE_P (cfg)) = 0; socket = (SERVER_SOCKET (cfg)); /* Remove any timeout that might be left over from earlier. */ ML_LOG_DEBUG (r, "clear socket timeout"); CVT_ERROR ((apr_socket_timeout_set (socket, (-1))), "clearing read timeout"); /* Convert environment variables to headers and send them. */ ML_LOG_DEBUG (r, "write env-var headers"); ap_add_cgi_vars (r); ap_add_common_vars (r); if ((r->subprocess_env) != 0) CVT_ERROR ((copy_headers ((r->subprocess_env), map_env_var_to_lisp_header, socket)), "writing to Lisp"); /* Send this before client headers so ASSOC can be used to grab it without worrying about some joker sending a server-id header of his own. (Robert Macomber) */ ML_LOG_DEBUG (r, "write headers"); CVT_ERROR ((write_lisp_header (socket, "server-id", (cfg->server_id))), "writing to Lisp"); CVT_ERROR ((write_lisp_header (socket, "server-baseversion", AP_SERVER_BASEVERSION)), "writing to Lisp"); CVT_ERROR ((write_lisp_header (socket, "modlisp-version", VERSION_STRING)), "writing to Lisp"); CVT_ERROR ((write_lisp_header (socket, "modlisp-major-version", "2")), "writing to Lisp"); /* Send all the remaining headers. */ if ((r->headers_in) != 0) CVT_ERROR ((copy_headers ((r->headers_in), map_header_to_lisp_header, socket)), "writing to Lisp"); request_content_length = apr_table_get(r->headers_in, "Content-Length"); /* Send the end-of-headers marker. */ ML_LOG_DEBUG (r, "write end-of-headers"); CVT_ERROR ((write_lisp_line (socket, "end")), "writing to Lisp"); /* Send the request entity. */ RELAY_HTTP_ERROR (ap_setup_client_block (r, REQUEST_CHUNKED_DECHUNK)); if (ap_should_client_block (r)) { char buffer [4096]; ML_LOG_DEBUG (r, "write entity"); while (1) { long n_read = (ap_get_client_block (r, buffer, (sizeof (buffer)))); if (n_read < 0) { ML_LOG_PERROR (r, "error reading from client"); close_lisp_socket (cfg); return (HTTP_INTERNAL_SERVER_ERROR); } /* for chunked case, when nread == 0, we will write * a terminating 0.*/ { apr_status_t status = APR_SUCCESS; /* if there's no Content-Type header, the data must be chunked */ if (request_content_length == NULL) status = write_lisp_data_chunk (socket, buffer, n_read); else if (n_read != 0) status = write_lisp_data (socket, buffer, n_read); if (APR_SUCCESS != status) { while ((ap_get_client_block (r, buffer, sizeof(buffer))) > 0) ; ML_LOG_ERROR (status, r, "writing to Lisp"); close_lisp_socket (cfg); return (HTTP_INTERNAL_SERVER_ERROR); } } if( n_read == 0) break; } } /* Set up read timeout so we don't hang forever if Lisp is wedged. */ ML_LOG_DEBUG (r, "set socket timeout"); CVT_ERROR ((apr_socket_timeout_set (socket, READ_TIMEOUT)), "setting read timeout"); /* Read the headers and process them. */ ML_LOG_DEBUG (r, "read headers"); while (1) { char header_name [4096]; char header_value [MAX_STRING_LEN]; CVT_ERROR ((read_lisp_line (socket, header_name, (sizeof (header_name)))), "reading from Lisp"); if ((strcasecmp (header_name, "end")) == 0) break; CVT_ERROR ((read_lisp_line (socket, header_value, (sizeof (header_value)))), "reading from Lisp"); if ((strcasecmp (header_name, "content-type")) == 0) { char * tmp = (apr_pstrdup ((r->pool), header_value)); ap_content_type_tolower (tmp); (r->content_type) = tmp; } else if ((strcasecmp (header_name, "status")) == 0) { (r->status) = (atoi (header_value)); (r->status_line) = (apr_pstrdup ((r->pool), header_value)); } else if ((strcasecmp (header_name, "location")) == 0) apr_table_set ((r->headers_out), header_name, header_value); else if ((strcasecmp (header_name, "content-length")) == 0) { apr_table_set ((r->headers_out), header_name, header_value); content_length = (atoi (header_value)); } else if ((strcasecmp (header_name, "lisp-content-length")) == 0) { content_length = (atoi (header_value)); } else if ((strcasecmp (header_name, "last-modified")) == 0) { apr_time_t mtime = (apr_date_parse_http (header_value)); r->mtime = mtime; ap_set_last_modified (r); } else if ((strcasecmp (header_name, "keep-socket")) == 0) keep_socket_p = (atoi (header_value)); else if ((strcasecmp (header_name, "log-emerg")) == 0) ap_log_error (APLOG_MARK, APLOG_EMERG, APR_SUCCESS, (r->server), "%s", header_value); else if ((strcasecmp (header_name, "log-alert")) == 0) ap_log_error (APLOG_MARK, APLOG_ALERT, APR_SUCCESS, (r->server), "%s", header_value); else if ((strcasecmp (header_name, "log-crit")) == 0) ap_log_error (APLOG_MARK, APLOG_CRIT, APR_SUCCESS, (r->server), "%s", header_value); else if ((strcasecmp (header_name, "log-error")) == 0) ap_log_error (APLOG_MARK, APLOG_ERR, APR_SUCCESS, (r->server), "%s", header_value); else if ((strcasecmp (header_name, "log-warning")) == 0) ap_log_error (APLOG_MARK, APLOG_WARNING, APR_SUCCESS, (r->server), "%s", header_value); else if ((strcasecmp (header_name, "log-notice")) == 0) ap_log_error (APLOG_MARK, APLOG_NOTICE, APR_SUCCESS, (r->server), "%s", header_value); else if ((strcasecmp (header_name, "log-info")) == 0) ap_log_error (APLOG_MARK, APLOG_INFO, APR_SUCCESS, (r->server), "%s", header_value); else if ((strcasecmp (header_name, "log-debug")) == 0) ap_log_error (APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, (r->server), "%s", header_value); else if ((strcasecmp (header_name, "log")) == 0) ap_log_error (APLOG_MARK, APLOG_ERR, APR_SUCCESS, (r->server), "%s", header_value); else if ((strcasecmp (header_name, "note")) == 0) { char * p = (strchr (header_value, ' ')); if (p != 0) { (*p++) = '\0'; apr_table_setn ((r->notes), (apr_pstrdup ((r->pool), header_value)), (apr_pstrdup ((r->pool), p))); } } else if ((strcasecmp (header_name, "set-cookie")) == 0) { apr_table_add ((r->headers_out), header_name, header_value); } else apr_table_set ((r->headers_out), header_name, header_value); } /* Copy the reply entity from Lisp to the client... */ // if (content_length > 0) { unsigned int n_read = 0; input_buffer_t * buffer; ML_LOG_DEBUG (r, "read entity"); CVT_ERROR ((get_input_buffer (socket, (&buffer))), "reading from Lisp"); while ((buffer->start) <= (buffer->end)) { apr_status_t fill_status; unsigned int n_bytes = ((buffer->end) - (buffer->start)); n_read += n_bytes; if ((content_length >= 0) && (n_read > content_length)) { n_bytes -= (n_read - content_length); n_read -= (n_read - content_length); } /* ...unless it's a HEAD request. */ if (!r->header_only && !write_client_data (r, (buffer->start), n_bytes)) { close_lisp_socket (cfg); return (HTTP_INTERNAL_SERVER_ERROR); } (buffer->start) += n_bytes; if (n_read == content_length) break; fill_status = fill_input_buffer (socket); if ((fill_status == APR_EOF) && (content_length < 0)) break; else CVT_ERROR (fill_status, "reading from Lisp"); } } if ((content_length < 0) || (!keep_socket_p)) CVT_ERROR ((close_lisp_socket (cfg)), "closing connection to Lisp"); else (SERVER_SOCKET_SAFE_P (cfg)) = 1; ML_LOG_DEBUG (r, "request finished"); return (OK); }
/** * Connect to the remote host */ apr_status_t do_connect(apr_pollset_t *pollset, apr_hash_t *ht, apr_pool_t *mp, const char *param) { apr_sockaddr_t *sa; apr_socket_t *s; apr_status_t rv; char **ptr; int port; ptr = str_split_char(param, ":"); if (ptr == NULL) { fprintf(stderr, "Get Null param!\n"); return APR_EINVAL; } // then convert param port = atoi(ptr[1]); if (port < 0) return APR_EINVAL; rv = apr_sockaddr_info_get(&sa, ptr[0], APR_INET, port, 0, mp); if (rv != APR_SUCCESS) { return rv; } rv = apr_socket_create(&s, sa->family, SOCK_STREAM, APR_PROTO_TCP, mp); if (rv != APR_SUCCESS) { return rv; } /* it is a good idea to specify socket options explicitly. * in this case, we make a blocking socket with timeout. */ apr_socket_opt_set(s, APR_SO_NONBLOCK, 1); apr_socket_timeout_set(s, DEF_SOCK_TIMEOUT); rv = apr_socket_connect(s, sa); if (rv != APR_SUCCESS) { printf("Connecting timeout!\n"); return rv; } /* see the tutorial about the reason why we have to specify options again */ apr_socket_opt_set(s, APR_SO_NONBLOCK, 1); apr_socket_timeout_set(s, 0); // It'll never block // Then, add it to hash table. -- "C"lient apr_hash_set(ht, s, APR_HASH_KEY_STRING, "C"); serv_ctx_t *serv_ctx = apr_palloc(mp, sizeof(serv_ctx_t)); apr_pollfd_t pfd = { mp, APR_POLL_SOCKET, APR_POLLIN, 0, { NULL }, serv_ctx }; pfd.desc.s = s; /* at first, we expect requests, so we poll APR_POLLIN event */ serv_ctx->status = SERV_RECV_REQUEST; serv_ctx->cb_func = recv_req_cb; serv_ctx->recv.is_firstline = TRUE; serv_ctx->mp = mp; apr_pollset_add(pollset, &pfd); free(ptr); return APR_SUCCESS; }
AP_DECLARE(void) ap_lingering_close(conn_rec *c) { char dummybuf[512]; apr_size_t nbytes = sizeof(dummybuf); apr_status_t rc; apr_int32_t timeout; apr_int32_t total_linger_time = 0; apr_socket_t *csd = ap_get_module_config(c->conn_config, &core_module); if (!csd) { return; } ap_update_child_status(c->sbh, SERVER_CLOSING, NULL); #ifdef NO_LINGCLOSE ap_flush_conn(c); /* just close it */ apr_socket_close(csd); return; #endif /* Close the connection, being careful to send out whatever is still * in our buffers. If possible, try to avoid a hard close until the * client has ACKed our FIN and/or has stopped sending us data. */ /* Send any leftover data to the client, but never try to again */ ap_flush_conn(c); if (c->aborted) { apr_socket_close(csd); return; } /* Shut down the socket for write, which will send a FIN * to the peer. */ if (apr_shutdown(csd, APR_SHUTDOWN_WRITE) != APR_SUCCESS || c->aborted) { apr_socket_close(csd); return; } /* Read all data from the peer until we reach "end-of-file" (FIN * from peer) or we've exceeded our overall timeout. If the client does * not send us bytes within 2 seconds (a value pulled from Apache 1.3 * which seems to work well), close the connection. */ timeout = apr_time_from_sec(SECONDS_TO_LINGER); apr_socket_timeout_set(csd, timeout); apr_socket_opt_set(csd, APR_INCOMPLETE_READ, 1); while (1) { nbytes = sizeof(dummybuf); rc = apr_recv(csd, dummybuf, &nbytes); if (rc != APR_SUCCESS || nbytes == 0) break; total_linger_time += SECONDS_TO_LINGER; if (total_linger_time >= MAX_SECS_TO_LINGER) { break; } } apr_socket_close(csd); return; }
apr_status_t test_server_run(test_baton_t *tb, apr_short_interval_time_t duration, apr_pool_t *pool) { apr_status_t status; apr_pollset_t *pollset; apr_int32_t num; const apr_pollfd_t *desc; /* create a new pollset */ status = apr_pollset_create(&pollset, 32, pool, 0); if (status != APR_SUCCESS) return status; /* Don't accept new connection while processing client connection. At least for present time.*/ if (tb->client_sock) { apr_pollfd_t pfd = { pool, APR_POLL_SOCKET, APR_POLLIN | APR_POLLOUT, 0, { NULL }, NULL }; pfd.desc.s = tb->client_sock; status = apr_pollset_add(pollset, &pfd); if (status != APR_SUCCESS) goto cleanup; } else { apr_pollfd_t pfd = { pool, APR_POLL_SOCKET, APR_POLLIN, 0, { NULL }, NULL }; pfd.desc.s = tb->serv_sock; status = apr_pollset_add(pollset, &pfd); if (status != APR_SUCCESS) goto cleanup; } status = apr_pollset_poll(pollset, APR_USEC_PER_SEC >> 1, &num, &desc); if (status != APR_SUCCESS) goto cleanup; while (num--) { if (desc->desc.s == tb->serv_sock) { status = apr_socket_accept(&tb->client_sock, tb->serv_sock, tb->pool); if (status != APR_SUCCESS) goto cleanup; apr_socket_opt_set(tb->client_sock, APR_SO_NONBLOCK, 1); apr_socket_timeout_set(tb->client_sock, 0); status = APR_SUCCESS; goto cleanup; } if (desc->desc.s == tb->client_sock) { /* Replay data to socket. */ status = replay(tb, pool); if (APR_STATUS_IS_EOF(status)) { apr_socket_close(tb->client_sock); tb->client_sock = NULL; } else if (APR_STATUS_IS_EAGAIN(status)) { status = APR_SUCCESS; } else if (status != APR_SUCCESS) { /* Real error. */ goto cleanup; } } desc++; } cleanup: apr_pollset_destroy(pollset); return status; }
static apr_status_t rfc1413_connect(apr_socket_t **newsock, conn_rec *conn, server_rec *srv) { apr_status_t rv; apr_sockaddr_t *localsa, *destsa; if ((rv = apr_sockaddr_info_get(&localsa, conn->local_ip, APR_UNSPEC, 0, /* ephemeral port */ 0, conn->pool)) != APR_SUCCESS) { /* This should not fail since we have a numeric address string * as the host. */ ap_log_error(APLOG_MARK, APLOG_CRIT, rv, srv, "rfc1413: apr_sockaddr_info_get(%s) failed", conn->local_ip); return rv; } if ((rv = apr_sockaddr_info_get(&destsa, conn->remote_ip, localsa->family, /* has to match */ RFC1413_PORT, 0, conn->pool)) != APR_SUCCESS) { /* This should not fail since we have a numeric address string * as the host. */ ap_log_error(APLOG_MARK, APLOG_CRIT, rv, srv, "rfc1413: apr_sockaddr_info_get(%s) failed", conn->remote_ip); return rv; } if ((rv = apr_socket_create(newsock, localsa->family, /* has to match */ SOCK_STREAM, conn->pool)) != APR_SUCCESS) { ap_log_error(APLOG_MARK, APLOG_CRIT, rv, srv, "rfc1413: error creating query socket"); return rv; } if ((rv = apr_socket_timeout_set(*newsock, apr_time_from_sec(ap_rfc1413_timeout))) != APR_SUCCESS) { ap_log_error(APLOG_MARK, APLOG_CRIT, rv, srv, "rfc1413: error setting query socket timeout"); apr_socket_close(*newsock); return rv; } /* * Bind the local and remote ends of the query socket to the same * IP addresses as the connection under investigation. We go * through all this trouble because the local or remote system * might have more than one network address. The RFC1413 etc. * client sends only port numbers; the server takes the IP * addresses from the query socket. */ if ((rv = apr_bind(*newsock, localsa)) != APR_SUCCESS) { ap_log_error(APLOG_MARK, APLOG_CRIT, rv, srv, "rfc1413: Error binding query socket to local port"); apr_socket_close(*newsock); return rv; } /* * errors from connect usually imply the remote machine doesn't support * the service; don't log such an error */ if ((rv = apr_connect(*newsock, destsa)) != APR_SUCCESS) { apr_socket_close(*newsock); return rv; } return APR_SUCCESS; }
/* This function connects to the server, then immediately closes the connection. * This permits the MPM to skip the poll when there is only one listening * socket, because it provides a alternate way to unblock an accept() when * the pod is used. */ static apr_status_t dummy_connection(ap_pod_t *pod) { char *srequest; apr_status_t rv; apr_socket_t *sock; apr_pool_t *p; apr_size_t len; /* create a temporary pool for the socket. pconf stays around too long */ rv = apr_pool_create(&p, pod->p); if (rv != APR_SUCCESS) { return rv; } rv = apr_socket_create(&sock, ap_listeners->bind_addr->family, SOCK_STREAM, 0, p); if (rv != APR_SUCCESS) { ap_log_error(APLOG_MARK, APLOG_WARNING, rv, ap_server_conf, "get socket to connect to listener"); apr_pool_destroy(p); return rv; } /* on some platforms (e.g., FreeBSD), the kernel won't accept many * queued connections before it starts blocking local connects... * we need to keep from blocking too long and instead return an error, * because the MPM won't want to hold up a graceful restart for a * long time */ rv = apr_socket_timeout_set(sock, apr_time_from_sec(3)); if (rv != APR_SUCCESS) { ap_log_error(APLOG_MARK, APLOG_WARNING, rv, ap_server_conf, "set timeout on socket to connect to listener"); apr_socket_close(sock); apr_pool_destroy(p); return rv; } rv = apr_socket_connect(sock, ap_listeners->bind_addr); if (rv != APR_SUCCESS) { int log_level = APLOG_WARNING; if (APR_STATUS_IS_TIMEUP(rv)) { /* probably some server processes bailed out already and there * is nobody around to call accept and clear out the kernel * connection queue; usually this is not worth logging */ log_level = APLOG_DEBUG; } ap_log_error(APLOG_MARK, log_level, rv, ap_server_conf, "connect to listener on %pI", ap_listeners->bind_addr); } /* Create the request string. We include a User-Agent so that * adminstrators can track down the cause of the odd-looking * requests in their logs. */ srequest = apr_pstrcat(p, "GET / HTTP/1.0\r\nUser-Agent: ", ap_get_server_banner(), " (internal dummy connection)\r\n\r\n", NULL); /* Since some operating systems support buffering of data or entire * requests in the kernel, we send a simple request, to make sure * the server pops out of a blocking accept(). */ /* XXX: This is HTTP specific. We should look at the Protocol for each * listener, and send the correct type of request to trigger any Accept * Filters. */ len = strlen(srequest); apr_socket_send(sock, srequest, &len); apr_socket_close(sock); apr_pool_destroy(p); return rv; }
static void im_tcp_accept(nx_module_t *module) { nx_im_tcp_conf_t *imconf; apr_socket_t *sock; apr_sockaddr_t *sa; char *ipstr; nx_module_input_t *input = NULL; apr_pool_t *pool = NULL; apr_status_t rv; nx_exception_t e; log_debug("im_tcp_accept"); imconf = (nx_im_tcp_conf_t *) module->config; pool = nx_pool_create_child(module->pool); try { if ( (rv = apr_socket_accept(&sock, imconf->listensock, pool)) != APR_SUCCESS ) { if ( APR_STATUS_IS_EAGAIN(rv) ) { nx_module_add_poll_event(module); apr_pool_destroy(pool); } else { throw(rv, "couldn't accept connection on %s:%u (statuscode: %d)", imconf->host, imconf->port, rv); } } if ( rv == APR_SUCCESS ) { CHECKERR_MSG(apr_socket_opt_set(sock, APR_SO_NONBLOCK, 1), "couldn't set SO_NONBLOCK on accepted socket"); CHECKERR_MSG(apr_socket_timeout_set(sock, 0), "couldn't set socket timeout on accepted socket"); if ( imconf->nodelay == TRUE ) { CHECKERR_MSG(apr_socket_opt_set(sock, APR_TCP_NODELAY, 1), "couldn't set TCP_NODELAY on accepted socket"); } CHECKERR_MSG(apr_socket_addr_get(&sa, APR_REMOTE, sock), "couldn't get info on accepted socket"); CHECKERR_MSG(apr_sockaddr_ip_get(&ipstr, sa), "couldn't get IP of accepted socket"); log_info("connection accepted from %s:%u", ipstr, sa->port); nx_module_pollset_add_socket(module, imconf->listensock, APR_POLLIN | APR_POLLHUP); input = nx_module_input_new(module, pool); input->desc_type = APR_POLL_SOCKET; input->desc.s = sock; input->inputfunc = imconf->inputfunc; CHECKERR_MSG(apr_socket_data_set(sock, input, "input", NULL), "couldn't set data on socket"); NX_DLIST_INSERT_TAIL(imconf->connections, input, link); nx_module_input_data_set(input, "recv_from_str", ipstr); nx_module_pollset_add_socket(module, input->desc.s, APR_POLLIN | APR_POLLHUP); } } catch(e) { apr_pool_destroy(pool); rethrow(e); } }
int main(int argc, char *argv[]) { apr_pool_t *p; apr_socket_t *sock; apr_status_t rv; apr_sockaddr_t *remote_sa; apr_initialize(); atexit(apr_terminate); apr_pool_create(&p, NULL); if (argc < 2) { exit(-1); } rv = apr_sockaddr_info_get(&remote_sa, "127.0.0.1", APR_UNSPEC, 8021, 0, p); if (rv != APR_SUCCESS) { exit(-1); } if (apr_socket_create(&sock, remote_sa->family, SOCK_STREAM, 0, p) != APR_SUCCESS) { exit(-1); } rv = apr_socket_timeout_set(sock, apr_time_from_sec(3)); if (rv) { exit(-1); } apr_socket_connect(sock, remote_sa); if (!strcmp("read", argv[1])) { char datarecv[STRLEN]; apr_size_t length = STRLEN; apr_status_t rv; memset(datarecv, 0, STRLEN); rv = apr_socket_recv(sock, datarecv, &length); apr_socket_close(sock); if (APR_STATUS_IS_TIMEUP(rv)) { exit(SOCKET_TIMEOUT); } if (strcmp(datarecv, DATASTR)) { exit(-1); } exit((int)length); } else if (!strcmp("write", argv[1]) || !strcmp("write_after_delay", argv[1])) { apr_size_t length = strlen(DATASTR); if (!strcmp("write_after_delay", argv[1])) { apr_sleep(apr_time_from_sec(2)); } apr_socket_send(sock, DATASTR, &length); apr_socket_close(sock); exit((int)length); } else if (!strcmp("close", argv[1])) { apr_socket_close(sock); exit(0); } exit(-1); }
apr_status_t rainx_http_req(struct req_params_store* rps) { const dav_resource* resource = rps->resource; char* remote_uri = rps->service_address; char* req_type = rps->req_type; char* header = rps->header; char* data = rps->data_to_send; int data_length = rps->data_to_send_size; char** reply = &(rps->reply); apr_pool_t *local_pool = rps->pool; dav_rainx_server_conf *server_conf = resource_get_server_config(resource); if (NULL == resource || NULL == remote_uri || NULL == req_type || NULL == server_conf) return -1; const gboolean is_get = (0 == g_strcmp0(req_type, "GET")); /* Isolating Rawx IP and port */ char *temp_remote_uri = apr_pstrdup(local_pool, remote_uri); char* last; char* full_remote_url = apr_strtok(temp_remote_uri, "/", &last); char* content_hexid = apr_pstrdup(local_pool, remote_uri + strlen(full_remote_url)); char* remote_ip = NULL; char* scope_id = NULL; apr_port_t remote_port; apr_parse_addr_port(&remote_ip, &scope_id, &remote_port, full_remote_url, local_pool); /* ------- */ /* Preparing the socket */ apr_socket_t* sock; apr_sockaddr_t* sockaddr; apr_status_t status; if ((status = apr_sockaddr_info_get(&sockaddr, remote_ip, APR_INET, remote_port, 0, local_pool)) != APR_SUCCESS) { DAV_DEBUG_REQ(resource->info->request, 0, "unable to connect to the rawx %s", full_remote_url); return status; } if ((status = apr_socket_create(&sock, sockaddr->family, SOCK_STREAM, APR_PROTO_TCP, local_pool)) != APR_SUCCESS) { DAV_DEBUG_REQ(resource->info->request, 0, "unable to create a socket to the rawx %s", full_remote_url); return status; } if ((status = apr_socket_timeout_set(sock, server_conf->socket_timeout)) != APR_SUCCESS) { DAV_DEBUG_REQ(resource->info->request, 0, "unable to set timeout for the socket to the rawx %s", full_remote_url); return status; } if ((status = apr_socket_connect(sock, sockaddr)) != APR_SUCCESS) { DAV_DEBUG_REQ(resource->info->request, 0, "unable to establish the connection to the rawx %s", full_remote_url); return status; } /* ------- */ /* Forging the message */ char* forged_header = apr_psprintf(local_pool, "%s %s HTTP/1.1\nHost: %s", req_type, content_hexid, full_remote_url); if (header) forged_header = apr_psprintf(local_pool, "%s\n%s", forged_header, header); if (data) forged_header = apr_psprintf(local_pool, "%s\nContent-Length: %d\n\n", forged_header, data_length); else forged_header = apr_psprintf(local_pool, "%s\n\n", forged_header); /* ------- */ /* Sending the message */ int remaining_to_send = strlen(forged_header); char* ptr_start = forged_header; apr_size_t send_buffer_size; while (remaining_to_send > 0) { if (remaining_to_send < REQUEST_BUFFER_SIZE) send_buffer_size = (apr_size_t)remaining_to_send; else send_buffer_size = REQUEST_BUFFER_SIZE; if ((status = apr_socket_send(sock, ptr_start, &send_buffer_size)) != APR_SUCCESS) { DAV_DEBUG_REQ(resource->info->request, 0, "failed to send the %s request to the rawx %s", req_type, full_remote_url); apr_status_t status_sav = status; apr_socket_close(sock); return status_sav; } remaining_to_send -= send_buffer_size; ptr_start = ptr_start + send_buffer_size; } if (NULL != data) { remaining_to_send = data_length; ptr_start = data; while (remaining_to_send > 0) { if (remaining_to_send < REQUEST_BUFFER_SIZE) send_buffer_size = (apr_size_t)remaining_to_send; else send_buffer_size = REQUEST_BUFFER_SIZE; if ((status = apr_socket_send(sock, ptr_start, &send_buffer_size)) != APR_SUCCESS) { DAV_DEBUG_REQ(resource->info->request, 0, "failed to send the %s request to the rawx %s", req_type, full_remote_url); apr_status_t status_sav = status; apr_socket_close(sock); return status_sav; } remaining_to_send -= send_buffer_size; ptr_start = ptr_start + send_buffer_size; } } DAV_DEBUG_REQ(resource->info->request, 0, "%s request to the rawx %s sent for the content %s", req_type, full_remote_url, content_hexid); /* ------ */ /* Getting the reply */ char* reply_ptr = *reply; apr_size_t total_size; if (!is_get) total_size = REPLY_BUFFER_SIZE; // PUT or DELETE else total_size = MAX_REPLY_HEADER_SIZE + data_length; // GET apr_size_t reply_size = (apr_size_t)total_size; apr_size_t total_replied_size; do { status = apr_socket_recv(sock, reply_ptr, &reply_size); reply_ptr += reply_size; total_replied_size = reply_ptr - *reply; /* Leave when OK, or error != timeout, or buffer full */ if (status == APR_EOF || (status == APR_SUCCESS && !is_get) || (reply_size == 0) || total_replied_size >= total_size) { break; } /* Take care of overflows! */ reply_size = total_size - total_replied_size; } while (total_replied_size < total_size); /* ------- */ apr_socket_close(sock); return status; }
/* Send the OCSP request serialized into BIO 'request' to the * responder at given server given by URI. Returns socket object or * NULL on error. */ static apr_socket_t *send_request(BIO *request, const apr_uri_t *uri, apr_interval_time_t timeout, conn_rec *c, apr_pool_t *p) { apr_status_t rv; apr_sockaddr_t *sa; apr_socket_t *sd; char buf[HUGE_STRING_LEN]; int len; rv = apr_sockaddr_info_get(&sa, uri->hostname, APR_UNSPEC, uri->port, 0, p); if (rv) { ap_log_cerror(APLOG_MARK, APLOG_ERR, rv, c, APLOGNO(01972) "could not resolve address of OCSP responder %s", uri->hostinfo); return NULL; } /* establish a connection to the OCSP responder */ ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, APLOGNO(01973) "connecting to OCSP responder '%s'", uri->hostinfo); /* Cycle through address until a connect() succeeds. */ for (; sa; sa = sa->next) { rv = apr_socket_create(&sd, sa->family, SOCK_STREAM, APR_PROTO_TCP, p); if (rv == APR_SUCCESS) { apr_socket_timeout_set(sd, timeout); rv = apr_socket_connect(sd, sa); if (rv == APR_SUCCESS) { break; } apr_socket_close(sd); } } if (sa == NULL) { ap_log_cerror(APLOG_MARK, APLOG_ERR, rv, c, APLOGNO(01974) "could not connect to OCSP responder '%s'", uri->hostinfo); apr_socket_close(sd); return NULL; } /* send the request and get a response */ ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, APLOGNO(01975) "sending request to OCSP responder"); while ((len = BIO_read(request, buf, sizeof buf)) > 0) { char *wbuf = buf; apr_size_t remain = len; do { apr_size_t wlen = remain; rv = apr_socket_send(sd, wbuf, &wlen); wbuf += remain; remain -= wlen; } while (rv == APR_SUCCESS && remain > 0); if (rv) { apr_socket_close(sd); ap_log_cerror(APLOG_MARK, APLOG_ERR, rv, c, APLOGNO(01976) "failed to send request to OCSP responder '%s'", uri->hostinfo); return NULL; } } return sd; }
int main(int argc, char *argv[]) { apr_pool_t *context; apr_socket_t *sock; apr_size_t length; apr_status_t stat; char datasend[STRLEN] = "Send data test"; char datarecv[STRLEN]; char msgbuf[80]; char *local_ipaddr, *remote_ipaddr; char *dest = "127.0.0.1"; apr_port_t local_port, remote_port; apr_interval_time_t timeout = apr_time_from_sec(2); apr_sockaddr_t *local_sa, *remote_sa; setbuf(stdout, NULL); if (argc > 1) { dest = argv[1]; } if (argc > 2) { timeout = atoi(argv[2]); } fprintf(stdout, "Initializing........."); if (apr_initialize() != APR_SUCCESS) { fprintf(stderr, "Something went wrong\n"); exit(-1); } fprintf(stdout, "OK\n"); atexit(apr_terminate); fprintf(stdout, "Creating context......."); if (apr_pool_create(&context, NULL) != APR_SUCCESS) { fprintf(stderr, "Something went wrong\n"); exit(-1); } fprintf(stdout, "OK\n"); fprintf(stdout,"\tClient: Making socket address..............."); if ((stat = apr_sockaddr_info_get(&remote_sa, dest, APR_UNSPEC, 8021, 0, context)) != APR_SUCCESS) { fprintf(stdout, "Failed!\n"); fprintf(stdout, "Address resolution failed for %s: %s\n", dest, apr_strerror(stat, msgbuf, sizeof(msgbuf))); exit(-1); } fprintf(stdout,"OK\n"); fprintf(stdout, "\tClient: Creating new socket......."); if (apr_socket_create(&sock, remote_sa->family, SOCK_STREAM, context) != APR_SUCCESS) { fprintf(stderr, "Couldn't create socket\n"); exit(-1); } fprintf(stdout, "OK\n"); fprintf(stdout, "\tClient: Setting socket timeout......."); stat = apr_socket_timeout_set(sock, timeout); if (stat) { fprintf(stderr, "Problem setting timeout: %d\n", stat); exit(-1); } fprintf(stdout, "OK\n"); fprintf(stdout, "\tClient: Connecting to socket......."); stat = apr_socket_connect(sock, remote_sa); if (stat != APR_SUCCESS) { apr_socket_close(sock); fprintf(stderr, "Could not connect: %s (%d)\n", apr_strerror(stat, msgbuf, sizeof(msgbuf)), stat); fflush(stderr); exit(-1); } fprintf(stdout, "OK\n"); apr_socket_addr_get(&remote_sa, APR_REMOTE, sock); apr_sockaddr_ip_get(&remote_ipaddr, remote_sa); apr_sockaddr_port_get(&remote_port, remote_sa); apr_socket_addr_get(&local_sa, APR_LOCAL, sock); apr_sockaddr_ip_get(&local_ipaddr, local_sa); apr_sockaddr_port_get(&local_port, local_sa); fprintf(stdout, "\tClient socket: %s:%u -> %s:%u\n", local_ipaddr, local_port, remote_ipaddr, remote_port); fprintf(stdout, "\tClient: Trying to send data over socket......."); length = STRLEN; if ((stat = apr_socket_send(sock, datasend, &length) != APR_SUCCESS)) { apr_socket_close(sock); fprintf(stderr, "Problem sending data: %s (%d)\n", apr_strerror(stat, msgbuf, sizeof(msgbuf)), stat); exit(-1); } fprintf(stdout, "OK\n"); length = STRLEN; fprintf(stdout, "\tClient: Trying to receive data over socket......."); if ((stat = apr_socket_recv(sock, datarecv, &length)) != APR_SUCCESS) { apr_socket_close(sock); fprintf(stderr, "Problem receiving data: %s (%d)\n", apr_strerror(stat, msgbuf, sizeof(msgbuf)), stat); exit(-1); } if (strcmp(datarecv, "Recv data test")) { apr_socket_close(sock); fprintf(stderr, "I did not receive the correct data %s\n", datarecv); exit(-1); } fprintf(stdout, "OK\n"); fprintf(stdout, "\tClient: Shutting down socket......."); if (apr_socket_shutdown(sock, APR_SHUTDOWN_WRITE) != APR_SUCCESS) { apr_socket_close(sock); fprintf(stderr, "Could not shutdown socket\n"); exit(-1); } fprintf(stdout, "OK\n"); fprintf(stdout, "\tClient: Closing down socket......."); if (apr_socket_close(sock) != APR_SUCCESS) { fprintf(stderr, "Could not shutdown socket\n"); exit(-1); } fprintf(stdout, "OK\n"); return 1; }
apr_status_t apr_socket_opt_set(apr_socket_t *sock, apr_int32_t opt, apr_int32_t on) { int one; apr_status_t rv; if (on) one = 1; else one = 0; switch(opt) { case APR_SO_KEEPALIVE: #ifdef SO_KEEPALIVE if (on != apr_is_option_set(sock->netmask, APR_SO_KEEPALIVE)) { if (setsockopt(sock->socketdes, SOL_SOCKET, SO_KEEPALIVE, (void *)&one, sizeof(int)) == -1) { return errno; } apr_set_option(&sock->netmask,APR_SO_KEEPALIVE, on); } #else return APR_ENOTIMPL; #endif break; case APR_SO_DEBUG: if (on != apr_is_option_set(sock->netmask, APR_SO_DEBUG)) { if (setsockopt(sock->socketdes, SOL_SOCKET, SO_DEBUG, (void *)&one, sizeof(int)) == -1) { return errno; } apr_set_option(&sock->netmask, APR_SO_DEBUG, on); } break; case APR_SO_REUSEADDR: if (on != apr_is_option_set(sock->netmask, APR_SO_REUSEADDR)) { if (setsockopt(sock->socketdes, SOL_SOCKET, SO_REUSEADDR, (void *)&one, sizeof(int)) == -1) { return errno; } apr_set_option(&sock->netmask, APR_SO_REUSEADDR, on); } break; case APR_SO_SNDBUF: #ifdef SO_SNDBUF if (setsockopt(sock->socketdes, SOL_SOCKET, SO_SNDBUF, (void *)&on, sizeof(int)) == -1) { return errno; } #else return APR_ENOTIMPL; #endif break; case APR_SO_RCVBUF: #ifdef SO_RCVBUF if (setsockopt(sock->socketdes, SOL_SOCKET, SO_RCVBUF, (void *)&on, sizeof(int)) == -1) { return errno; } #else return APR_ENOTIMPL; #endif break; case APR_SO_NONBLOCK: if (apr_is_option_set(sock->netmask, APR_SO_NONBLOCK) != on) { if (on) { if ((rv = sononblock(sock->socketdes)) != APR_SUCCESS) return rv; } else { if ((rv = soblock(sock->socketdes)) != APR_SUCCESS) return rv; } apr_set_option(&sock->netmask, APR_SO_NONBLOCK, on); } break; case APR_SO_LINGER: #ifdef SO_LINGER if (apr_is_option_set(sock->netmask, APR_SO_LINGER) != on) { struct linger li; li.l_onoff = on; li.l_linger = APR_MAX_SECS_TO_LINGER; if (setsockopt(sock->socketdes, SOL_SOCKET, SO_LINGER, (char *) &li, sizeof(struct linger)) == -1) { return errno; } apr_set_option(&sock->netmask, APR_SO_LINGER, on); } #else return APR_ENOTIMPL; #endif break; case APR_SO_TIMEOUT: /* XXX: To be deprecated */ return apr_socket_timeout_set(sock, on); break; case APR_TCP_NODELAY: #if defined(TCP_NODELAY) if (apr_is_option_set(sock->netmask, APR_TCP_NODELAY) != on) { int optlevel = IPPROTO_TCP; int optname = TCP_NODELAY; #if APR_HAVE_SCTP if (sock->protocol == IPPROTO_SCTP) { optlevel = IPPROTO_SCTP; optname = SCTP_NODELAY; } #endif if (setsockopt(sock->socketdes, optlevel, optname, (void *)&on, sizeof(int)) == -1) { return errno; } apr_set_option(&sock->netmask, APR_TCP_NODELAY, on); } #else /* BeOS pre-BONE has TCP_NODELAY set by default. * As it can't be turned off we might as well check if they're asking * for it to be turned on! */ #ifdef BEOS if (on == 1) return APR_SUCCESS; else #endif return APR_ENOTIMPL; #endif break; case APR_TCP_NOPUSH: #if APR_TCP_NOPUSH_FLAG if (apr_is_option_set(sock->netmask, APR_TCP_NOPUSH) != on) { int optlevel = IPPROTO_TCP; int optname = TCP_NODELAY; #if APR_HAVE_SCTP if (sock->protocol == IPPROTO_SCTP) { optlevel = IPPROTO_SCTP; optname = SCTP_NODELAY; } #endif /* OK we're going to change some settings here... */ /* TCP_NODELAY is mutually exclusive, so do we have it set? */ if (apr_is_option_set(sock->netmask, APR_TCP_NODELAY) == 1 && on) { /* If we want to set NOPUSH then if we have the TCP_NODELAY * flag set we need to switch it off... */ int tmpflag = 0; if (setsockopt(sock->socketdes, optlevel, optname, (void*)&tmpflag, sizeof(int)) == -1) { return errno; } apr_set_option(&sock->netmask, APR_RESET_NODELAY, 1); apr_set_option(&sock->netmask, APR_TCP_NODELAY, 0); } else if (on) { apr_set_option(&sock->netmask, APR_RESET_NODELAY, 0); } /* OK, now we can just set the TCP_NOPUSH flag accordingly...*/ if (setsockopt(sock->socketdes, IPPROTO_TCP, APR_TCP_NOPUSH_FLAG, (void*)&on, sizeof(int)) == -1) { return errno; } apr_set_option(&sock->netmask, APR_TCP_NOPUSH, on); if (!on && apr_is_option_set(sock->netmask, APR_RESET_NODELAY)) { int tmpflag = 1; if (setsockopt(sock->socketdes, optlevel, optname, (void*)&tmpflag, sizeof(int)) == -1) { return errno; } apr_set_option(&sock->netmask, APR_RESET_NODELAY,0); apr_set_option(&sock->netmask, APR_TCP_NODELAY, 1); } } #else return APR_ENOTIMPL; #endif break; case APR_INCOMPLETE_READ: apr_set_option(&sock->netmask, APR_INCOMPLETE_READ, on); break; case APR_IPV6_V6ONLY: #if APR_HAVE_IPV6 && defined(IPV6_V6ONLY) /* we don't know the initial setting of this option, * so don't check sock->netmask since that optimization * won't work */ if (setsockopt(sock->socketdes, IPPROTO_IPV6, IPV6_V6ONLY, (void *)&on, sizeof(int)) == -1) { return errno; } apr_set_option(&sock->netmask, APR_IPV6_V6ONLY, on); #else return APR_ENOTIMPL; #endif break; default: return APR_EINVAL; } return APR_SUCCESS; }
void LLPluginProcessParent::idle(void) { bool idle_again; do { // process queued messages mIncomingQueueMutex.lock(); while(!mIncomingQueue.empty()) { LLPluginMessage message = mIncomingQueue.front(); mIncomingQueue.pop(); mIncomingQueueMutex.unlock(); receiveMessage(message); mIncomingQueueMutex.lock(); } mIncomingQueueMutex.unlock(); // Give time to network processing if(mMessagePipe) { // Drain any queued outgoing messages mMessagePipe->pumpOutput(); // Only do input processing here if this instance isn't in a pollset. if(!mPolledInput) { mMessagePipe->pumpInput(); } } if(mState <= STATE_RUNNING) { if(APR_STATUS_IS_EOF(mSocketError)) { // Plugin socket was closed. This covers both normal plugin termination and plugin crashes. errorState(); } else if(mSocketError != APR_SUCCESS) { // The socket is in an error state -- the plugin is gone. LL_WARNS("Plugin") << "Socket hit an error state (" << mSocketError << ")" << LL_ENDL; errorState(); } } // If a state needs to go directly to another state (as a performance enhancement), it can set idle_again to true after calling setState(). // USE THIS CAREFULLY, since it can starve other code. Specifically make sure there's no way to get into a closed cycle and never return. // When in doubt, don't do it. idle_again = false; switch(mState) { case STATE_UNINITIALIZED: break; case STATE_INITIALIZED: { apr_status_t status = APR_SUCCESS; apr_sockaddr_t* addr = NULL; mListenSocket = LLSocket::create(gAPRPoolp, LLSocket::STREAM_TCP); mBoundPort = 0; // This code is based on parts of LLSocket::create() in lliosocket.cpp. status = apr_sockaddr_info_get( &addr, "127.0.0.1", APR_INET, mPortToBind, // port 0 = ephemeral ("find me a port") 0, gAPRPoolp); if(ll_apr_warn_status(status)) { killSockets(); errorState(); break; } // This allows us to reuse the address on quick down/up. This is unlikely to create problems. ll_apr_warn_status(apr_socket_opt_set(mListenSocket->getSocket(), APR_SO_REUSEADDR, 1)); status = apr_socket_bind(mListenSocket->getSocket(), addr); if(ll_apr_warn_status(status)) { killSockets(); errorState(); break; } // Get the actual port the socket was bound to { apr_sockaddr_t* bound_addr = NULL; if(ll_apr_warn_status(apr_socket_addr_get(&bound_addr, APR_LOCAL, mListenSocket->getSocket()))) { killSockets(); errorState(); break; } mBoundPort = bound_addr->port; if(mBoundPort == 0) { LL_WARNS("Plugin") << "Bound port number unknown, bailing out." << LL_ENDL; killSockets(); // <ND> FIRE-3877; Some drivers, eg bigfoot. Refuse to tell us which port is used when the socket is bound on port 0 (= choose a free port). // If not out of retry attempts, choose a random port between 5500 - 60000 and try again. if( mBindRetries > 10 ) //In theory we could have bad luck and randomly draft already used ports each try. In practice we already deal with a buggy driver anyway. So just fail instead hogging resources in a loop. errorState(); else { ++mBindRetries; mPortToBind = ll_rand(55000)+5000; // Ports < 4096 are reserved for root (at least on BSD like systems), do never touch them. setState( STATE_INITIALIZED ); idle_again = true; // Just try a new loop to bind the socket } // </ND> break; } } LL_DEBUGS("Plugin") << "Bound tcp socket to port: " << addr->port << LL_ENDL; // Make the listen socket non-blocking status = apr_socket_opt_set(mListenSocket->getSocket(), APR_SO_NONBLOCK, 1); if(ll_apr_warn_status(status)) { killSockets(); errorState(); break; } apr_socket_timeout_set(mListenSocket->getSocket(), 0); if(ll_apr_warn_status(status)) { killSockets(); errorState(); break; } // If it's a stream based socket, we need to tell the OS // to keep a queue of incoming connections for ACCEPT. status = apr_socket_listen( mListenSocket->getSocket(), 10); // FIXME: Magic number for queue size if(ll_apr_warn_status(status)) { killSockets(); errorState(); break; } // If we got here, we're listening. setState(STATE_LISTENING); } break; case STATE_LISTENING: { // Launch the plugin process. // Only argument to the launcher is the port number we're listening on mProcessParams.args.add(stringize(mBoundPort)); if (! (mProcess = LLProcess::create(mProcessParams))) { errorState(); } else { if(mDebug) { #if LL_DARWIN // If we're set to debug, start up a gdb instance in a new terminal window and have it attach to the plugin process and continue. // The command we're constructing would look like this on the command line: // osascript -e 'tell application "Terminal"' -e 'set win to do script "gdb -pid 12345"' -e 'do script "continue" in win' -e 'end tell' LLProcess::Params params; params.executable = "/usr/bin/osascript"; params.args.add("-e"); params.args.add("tell application \"Terminal\""); params.args.add("-e"); params.args.add(STRINGIZE("set win to do script \"gdb -pid " << mProcess->getProcessID() << "\"")); params.args.add("-e"); params.args.add("do script \"continue\" in win"); params.args.add("-e"); params.args.add("end tell"); mDebugger = LLProcess::create(params); #endif } // This will allow us to time out if the process never starts. mHeartbeat.start(); mHeartbeat.setTimerExpirySec(mPluginLaunchTimeout); setState(STATE_LAUNCHED); } } break; case STATE_LAUNCHED: // waiting for the plugin to connect if(pluginLockedUpOrQuit()) { errorState(); } else { // Check for the incoming connection. if(accept()) { // Stop listening on the server port mListenSocket.reset(); setState(STATE_CONNECTED); } } break; case STATE_CONNECTED: // waiting for hello message from the plugin if(pluginLockedUpOrQuit()) { errorState(); } break; case STATE_HELLO: LL_DEBUGS("Plugin") << "received hello message" << LL_ENDL; // Send the message to load the plugin { LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "load_plugin"); message.setValue("file", mPluginFile); message.setValue("dir", mPluginDir); sendMessage(message); } setState(STATE_LOADING); break; case STATE_LOADING: // The load_plugin_response message will kick us from here into STATE_RUNNING if(pluginLockedUpOrQuit()) { errorState(); } break; case STATE_RUNNING: if(pluginLockedUpOrQuit()) { errorState(); } break; case STATE_EXITING: if (! LLProcess::isRunning(mProcess)) { setState(STATE_CLEANUP); } else if(pluginLockedUp()) { LL_WARNS("Plugin") << "timeout in exiting state, bailing out" << LL_ENDL; errorState(); } break; case STATE_LAUNCH_FAILURE: if(mOwner != NULL) { mOwner->pluginLaunchFailed(); } setState(STATE_CLEANUP); break; case STATE_ERROR: if(mOwner != NULL) { mOwner->pluginDied(); } setState(STATE_CLEANUP); break; case STATE_CLEANUP: LLProcess::kill(mProcess); killSockets(); setState(STATE_DONE); break; case STATE_DONE: // just sit here. break; } } while (idle_again); }
static int client(apr_pool_t *p, client_socket_mode_t socket_mode, const char *host, int start_server) { apr_status_t rv, tmprv; apr_socket_t *sock; char buf[120]; apr_file_t *f = NULL; apr_size_t len; apr_size_t expected_len; apr_off_t current_file_offset; apr_hdtr_t hdtr; struct iovec headers[3]; struct iovec trailers[3]; apr_size_t bytes_read; apr_pollset_t *pset; apr_int32_t nsocks; int connect_tries = 1; int i; int family; apr_sockaddr_t *destsa; apr_proc_t server; apr_interval_time_t connect_retry_interval = apr_time_from_msec(50); if (start_server) { spawn_server(p, &server); connect_tries = 5; /* give it a chance to start up */ } create_testfile(p, TESTFILE); rv = apr_file_open(&f, TESTFILE, APR_FOPEN_READ, 0, p); if (rv != APR_SUCCESS) { aprerr("apr_file_open()", rv); } if (!host) { host = "127.0.0.1"; } family = APR_INET; rv = apr_sockaddr_info_get(&destsa, host, family, TESTSF_PORT, 0, p); if (rv != APR_SUCCESS) { aprerr("apr_sockaddr_info_get()", rv); } while (connect_tries--) { apr_setup(p, &sock, &family); rv = apr_socket_connect(sock, destsa); if (connect_tries && APR_STATUS_IS_ECONNREFUSED(rv)) { apr_status_t tmprv = apr_socket_close(sock); if (tmprv != APR_SUCCESS) { aprerr("apr_socket_close()", tmprv); } apr_sleep(connect_retry_interval); connect_retry_interval *= 2; } else { break; } } if (rv != APR_SUCCESS) { aprerr("apr_socket_connect()", rv); } switch(socket_mode) { case BLK: /* leave it blocking */ break; case NONBLK: /* set it non-blocking */ rv = apr_socket_opt_set(sock, APR_SO_NONBLOCK, 1); if (rv != APR_SUCCESS) { aprerr("apr_socket_opt_set(APR_SO_NONBLOCK)", rv); } break; case TIMEOUT: /* set a timeout */ rv = apr_socket_timeout_set(sock, 100 * APR_USEC_PER_SEC); if (rv != APR_SUCCESS) { aprerr("apr_socket_opt_set(APR_SO_NONBLOCK)", rv); exit(1); } break; default: assert(1 != 1); } printf("Sending the file...\n"); hdtr.headers = headers; hdtr.numheaders = 3; hdtr.headers[0].iov_base = HDR1; hdtr.headers[0].iov_len = strlen(hdtr.headers[0].iov_base); hdtr.headers[1].iov_base = HDR2; hdtr.headers[1].iov_len = strlen(hdtr.headers[1].iov_base); hdtr.headers[2].iov_base = malloc(HDR3_LEN); assert(hdtr.headers[2].iov_base); memset(hdtr.headers[2].iov_base, HDR3_CHAR, HDR3_LEN); hdtr.headers[2].iov_len = HDR3_LEN; hdtr.trailers = trailers; hdtr.numtrailers = 3; hdtr.trailers[0].iov_base = TRL1; hdtr.trailers[0].iov_len = strlen(hdtr.trailers[0].iov_base); hdtr.trailers[1].iov_base = TRL2; hdtr.trailers[1].iov_len = strlen(hdtr.trailers[1].iov_base); hdtr.trailers[2].iov_base = malloc(TRL3_LEN); memset(hdtr.trailers[2].iov_base, TRL3_CHAR, TRL3_LEN); assert(hdtr.trailers[2].iov_base); hdtr.trailers[2].iov_len = TRL3_LEN; expected_len = strlen(HDR1) + strlen(HDR2) + HDR3_LEN + strlen(TRL1) + strlen(TRL2) + TRL3_LEN + FILE_LENGTH; if (socket_mode == BLK) { current_file_offset = 0; len = FILE_LENGTH; rv = apr_socket_sendfile(sock, f, &hdtr, ¤t_file_offset, &len, 0); if (rv != APR_SUCCESS) { aprerr("apr_socket_sendfile()", rv); } printf("apr_socket_sendfile() updated offset with %ld\n", (long int)current_file_offset); printf("apr_socket_sendfile() updated len with %ld\n", (long int)len); printf("bytes really sent: %" APR_SIZE_T_FMT "\n", expected_len); if (len != expected_len) { fprintf(stderr, "apr_socket_sendfile() didn't report the correct " "number of bytes sent!\n"); exit(1); } } else { /* non-blocking... wooooooo */ apr_size_t total_bytes_sent; apr_pollfd_t pfd; pset = NULL; rv = apr_pollset_create(&pset, 1, p, 0); assert(!rv); pfd.p = p; pfd.desc_type = APR_POLL_SOCKET; pfd.reqevents = APR_POLLOUT; pfd.rtnevents = 0; pfd.desc.s = sock; pfd.client_data = NULL; rv = apr_pollset_add(pset, &pfd); assert(!rv); total_bytes_sent = 0; current_file_offset = 0; len = FILE_LENGTH; do { apr_size_t tmplen; tmplen = len; /* bytes remaining to send from the file */ printf("Calling apr_socket_sendfile()...\n"); printf("Headers (%d):\n", hdtr.numheaders); for (i = 0; i < hdtr.numheaders; i++) { printf("\t%ld bytes (%c)\n", (long)hdtr.headers[i].iov_len, *(char *)hdtr.headers[i].iov_base); } printf("File: %ld bytes from offset %ld\n", (long)tmplen, (long)current_file_offset); printf("Trailers (%d):\n", hdtr.numtrailers); for (i = 0; i < hdtr.numtrailers; i++) { printf("\t%ld bytes\n", (long)hdtr.trailers[i].iov_len); } rv = apr_socket_sendfile(sock, f, &hdtr, ¤t_file_offset, &tmplen, 0); printf("apr_socket_sendfile()->%d, sent %ld bytes\n", rv, (long)tmplen); if (rv) { if (APR_STATUS_IS_EAGAIN(rv)) { assert(tmplen == 0); nsocks = 1; tmprv = apr_pollset_poll(pset, -1, &nsocks, NULL); assert(!tmprv); assert(nsocks == 1); /* continue; */ } } total_bytes_sent += tmplen; /* Adjust hdtr to compensate for partially-written * data. */ /* First, skip over any header data which might have * been written. */ while (tmplen && hdtr.numheaders) { if (tmplen >= hdtr.headers[0].iov_len) { tmplen -= hdtr.headers[0].iov_len; --hdtr.numheaders; ++hdtr.headers; } else { hdtr.headers[0].iov_len -= tmplen; hdtr.headers[0].iov_base = (char*) hdtr.headers[0].iov_base + tmplen; tmplen = 0; } } /* Now, skip over any file data which might have been * written. */ if (tmplen <= len) { current_file_offset += tmplen; len -= tmplen; tmplen = 0; } else { tmplen -= len; len = 0; current_file_offset = 0; } /* Last, skip over any trailer data which might have * been written. */ while (tmplen && hdtr.numtrailers) { if (tmplen >= hdtr.trailers[0].iov_len) { tmplen -= hdtr.trailers[0].iov_len; --hdtr.numtrailers; ++hdtr.trailers; } else { hdtr.trailers[0].iov_len -= tmplen; hdtr.trailers[0].iov_base = (char *)hdtr.trailers[0].iov_base + tmplen; tmplen = 0; } } } while (total_bytes_sent < expected_len && (rv == APR_SUCCESS || (APR_STATUS_IS_EAGAIN(rv) && socket_mode != TIMEOUT))); if (total_bytes_sent != expected_len) { fprintf(stderr, "client problem: sent %ld of %ld bytes\n", (long)total_bytes_sent, (long)expected_len); exit(1); } if (rv) { fprintf(stderr, "client problem: rv %d\n", rv); exit(1); } } current_file_offset = 0; rv = apr_file_seek(f, APR_CUR, ¤t_file_offset); if (rv != APR_SUCCESS) { aprerr("apr_file_seek()", rv); } printf("After apr_socket_sendfile(), the kernel file pointer is " "at offset %ld.\n", (long int)current_file_offset); rv = apr_socket_shutdown(sock, APR_SHUTDOWN_WRITE); if (rv != APR_SUCCESS) { aprerr("apr_socket_shutdown()", rv); } /* in case this is the non-blocking test, set socket timeout; * we're just waiting for EOF */ rv = apr_socket_timeout_set(sock, apr_time_from_sec(3)); if (rv != APR_SUCCESS) { aprerr("apr_socket_timeout_set()", rv); } bytes_read = 1; rv = apr_socket_recv(sock, buf, &bytes_read); if (rv != APR_EOF) { aprerr("apr_socket_recv() (expected APR_EOF)", rv); } if (bytes_read != 0) { fprintf(stderr, "We expected to get 0 bytes read with APR_EOF\n" "but instead we read %ld bytes.\n", (long int)bytes_read); exit(1); } printf("client: apr_socket_sendfile() worked as expected!\n"); rv = apr_file_remove(TESTFILE, p); if (rv != APR_SUCCESS) { aprerr("apr_file_remove()", rv); } if (start_server) { apr_exit_why_e exitwhy; apr_size_t nbytes; char responsebuf[1024]; int exitcode; rv = apr_file_pipe_timeout_set(server.out, apr_time_from_sec(2)); if (rv != APR_SUCCESS) { aprerr("apr_file_pipe_timeout_set()", rv); } nbytes = sizeof(responsebuf); rv = apr_file_read(server.out, responsebuf, &nbytes); if (rv != APR_SUCCESS) { aprerr("apr_file_read() messages from server", rv); } printf("%.*s", (int)nbytes, responsebuf); rv = apr_proc_wait(&server, &exitcode, &exitwhy, APR_WAIT); if (rv != APR_CHILD_DONE) { aprerr("apr_proc_wait() (expected APR_CHILD_DONE)", rv); } if (exitcode != 0) { fprintf(stderr, "sendfile server returned %d\n", exitcode); exit(1); } } return 0; }
//本函数只处理一次buf读取操作,loop在caller中执行 static apr_status_t socket_bucket_read(apr_bucket *a, const char **str, apr_size_t *len, apr_read_type_e block) { //把数据从a->data中读入到a->list中的node空间中 apr_socket_t *p = a->data; char *buf; apr_status_t rv; apr_interval_time_t timeout; if (block == APR_NONBLOCK_READ) { apr_socket_timeout_get(p, &timeout); apr_socket_timeout_set(p, 0); } *str = NULL; *len = APR_BUCKET_BUFF_SIZE; buf = apr_bucket_alloc(*len, a->list); /* XXX: check for failure? */ rv = apr_socket_recv(p, buf, len); if (block == APR_NONBLOCK_READ) { apr_socket_timeout_set(p, timeout); } if (rv != APR_SUCCESS && rv != APR_EOF) { apr_bucket_free(buf); return rv; } /* * If there's more to read we have to keep the rest of the socket * for later. XXX: Note that more complicated bucket types that * refer to data not in memory and must therefore have a read() * function similar to this one should be wary of copying this * code because if they have a destroy function they probably * want to migrate the bucket's subordinate structure from the * old bucket to a raw new one and adjust it as appropriate, * rather than destroying the old one and creating a completely * new bucket. * 如果read后还有剩余,则需要保留socket剩余部分下次再读。 * 类似这样的需要一个read()操作的非内存bucket,请谨慎copy当前代码, * 原因见上面解释 * * * Even if there is nothing more to read, don't close the socket here * as we have to use it to send any response :) We could shut it * down for reading, but there is no benefit to doing so. * read完成后不需要close/shut down socket * * */ if (*len > 0) { apr_bucket_heap *h; /* Change the current bucket to refer to what we read */ //把当前读取的那部分数据组织成一个heap bucket,并返回起始地址 a = apr_bucket_heap_make(a, buf, *len, apr_bucket_free); h = a->data; h->alloc_len = APR_BUCKET_BUFF_SIZE; /* note the real buffer size */ *str = buf; //剩下的p作为一个新的socket bucket APR_BUCKET_INSERT_AFTER(a, apr_bucket_socket_create(p, a->list)); } else { apr_bucket_free(buf); a = apr_bucket_immortal_make(a, "", 0); *str = a->data; } return APR_SUCCESS; }
static mrcp_connection_t* mrcp_client_agent_connection_create(mrcp_connection_agent_t *agent, mrcp_control_descriptor_t *descriptor) { char *local_ip = NULL; char *remote_ip = NULL; mrcp_connection_t *connection = mrcp_connection_create(); apr_sockaddr_info_get(&connection->r_sockaddr,descriptor->ip.buf,APR_INET,descriptor->port,0,connection->pool); if(!connection->r_sockaddr) { mrcp_connection_destroy(connection); return NULL; } if(apr_socket_create(&connection->sock,connection->r_sockaddr->family,SOCK_STREAM,APR_PROTO_TCP,connection->pool) != APR_SUCCESS) { mrcp_connection_destroy(connection); return NULL; } apr_socket_opt_set(connection->sock, APR_SO_NONBLOCK, 0); apr_socket_timeout_set(connection->sock, -1); apr_socket_opt_set(connection->sock, APR_SO_REUSEADDR, 1); if(apr_socket_connect(connection->sock, connection->r_sockaddr) != APR_SUCCESS) { apr_socket_close(connection->sock); mrcp_connection_destroy(connection); return NULL; } if(apr_socket_addr_get(&connection->l_sockaddr,APR_LOCAL,connection->sock) != APR_SUCCESS) { apr_socket_close(connection->sock); mrcp_connection_destroy(connection); return NULL; } apr_sockaddr_ip_get(&local_ip,connection->l_sockaddr); apr_sockaddr_ip_get(&remote_ip,connection->r_sockaddr); connection->id = apr_psprintf(connection->pool,"%s:%hu <-> %s:%hu", local_ip,connection->l_sockaddr->port, remote_ip,connection->r_sockaddr->port); memset(&connection->sock_pfd,0,sizeof(apr_pollfd_t)); connection->sock_pfd.desc_type = APR_POLL_SOCKET; connection->sock_pfd.reqevents = APR_POLLIN; connection->sock_pfd.desc.s = connection->sock; connection->sock_pfd.client_data = connection; if(apt_poller_task_descriptor_add(agent->task, &connection->sock_pfd) != TRUE) { apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Add to Pollset %s",connection->id); apr_socket_close(connection->sock); mrcp_connection_destroy(connection); return NULL; } apt_log(APT_LOG_MARK,APT_PRIO_NOTICE,"Established TCP/MRCPv2 Connection %s",connection->id); connection->agent = agent; APR_RING_INSERT_TAIL(&agent->connection_list,connection,mrcp_connection_t,link); connection->parser = mrcp_parser_create(agent->resource_factory,connection->pool); connection->generator = mrcp_generator_create(agent->resource_factory,connection->pool); connection->tx_buffer_size = agent->tx_buffer_size; connection->tx_buffer = apr_palloc(connection->pool,connection->tx_buffer_size+1); connection->rx_buffer_size = agent->rx_buffer_size; connection->rx_buffer = apr_palloc(connection->pool,connection->rx_buffer_size+1); apt_text_stream_init(&connection->rx_stream,connection->rx_buffer,connection->rx_buffer_size); if(apt_log_masking_get() != APT_LOG_MASKING_NONE) { connection->verbose = FALSE; mrcp_parser_verbose_set(connection->parser,TRUE); mrcp_generator_verbose_set(connection->generator,TRUE); } return connection; }