static HttpConn *openConnection(HttpConn *conn, struct MprSsl *ssl) { Http *http; HttpUri *uri; MprSocket *sp; char *ip; int port, rc; assert(conn); http = conn->http; uri = conn->tx->parsedUri; if (!uri->host) { ip = (http->proxyHost) ? http->proxyHost : http->defaultClientHost; port = (http->proxyHost) ? http->proxyPort : http->defaultClientPort; } else { ip = (http->proxyHost) ? http->proxyHost : uri->host; port = (http->proxyHost) ? http->proxyPort : uri->port; } if (port == 0) { port = (uri->secure) ? 443 : 80; } if (conn && conn->sock) { if (conn->keepAliveCount-- <= 0 || port != conn->port || strcmp(ip, conn->ip) != 0 || uri->secure != (conn->sock->ssl != 0) || conn->sock->ssl != ssl) { /* Cannot reuse current socket. Close and open a new one below. */ mprCloseSocket(conn->sock, 0); conn->sock = 0; } else { httpTrace(conn, "connection.reuse", "context", "keepAlive:%d", conn->keepAliveCount); } } if (conn->sock) { return conn; } /* New socket */ if ((sp = mprCreateSocket()) == 0) { httpError(conn, HTTP_ABORT | HTTP_CODE_COMMS_ERROR, "Cannot create socket for %s", httpUriToString(uri, 0)); return 0; } if ((rc = mprConnectSocket(sp, ip, port, MPR_SOCKET_NODELAY)) < 0) { httpError(conn, HTTP_ABORT | HTTP_CODE_COMMS_ERROR, "Cannot open socket on %s:%d", ip, port); return 0; } conn->sock = sp; conn->ip = sclone(ip); conn->port = port; conn->keepAliveCount = (conn->limits->keepAliveMax) ? conn->limits->keepAliveMax : 0; #if ME_COM_SSL /* Must be done even if using keep alive for repeat SSL requests */ if (uri->secure) { char *peerName; if (ssl == 0) { ssl = mprCreateSsl(0); } peerName = isdigit(uri->host[0]) ? 0 : uri->host; if (mprUpgradeSocket(sp, ssl, peerName) < 0) { conn->errorMsg = sp->errorMsg; httpTrace(conn, "connection.upgrade.error", "error", "msg:'Cannot perform SSL upgrade. %s'", conn->errorMsg); return 0; } if (sp->peerCert) { httpTrace(conn, "context", "connection.ssl", "msg:'Connection secured with peer certificate', " \ "secure:true,cipher:'%s',peerName:'%s',subject:'%s',issuer:'%s'", sp->cipher, sp->peerName, sp->peerCert, sp->peerCertIssuer); } } #endif #if ME_HTTP_WEB_SOCKETS if (uri->webSockets && httpUpgradeWebSocket(conn) < 0) { conn->errorMsg = sp->errorMsg; return 0; } #endif httpTrace(conn, "connection.peer", "context", "peer:'%s:%d'", conn->ip, conn->port); return conn; }
/* Accept a new client connection on a new socket. This will come in on a worker thread with a new dispatcher dedicated to this connection. */ PUBLIC HttpConn *httpAcceptConn(HttpEndpoint *endpoint, MprEvent *event) { Http *http; HttpConn *conn; HttpAddress *address; MprSocket *sock; int64 value; assert(event); assert(event->dispatcher); assert(endpoint); sock = event->sock; http = endpoint->http; if (mprShouldDenyNewRequests()) { mprCloseSocket(sock, 0); return 0; } if ((conn = httpCreateConn(endpoint, event->dispatcher)) == 0) { mprCloseSocket(sock, 0); return 0; } conn->notifier = endpoint->notifier; conn->async = endpoint->async; conn->endpoint = endpoint; conn->sock = sock; conn->port = sock->port; conn->ip = sclone(sock->ip); if ((value = httpMonitorEvent(conn, HTTP_COUNTER_ACTIVE_CONNECTIONS, 1)) > conn->limits->connectionsMax) { httpTrace(conn, "connection.accept.error", "error", "msg:'Too many concurrent connections',active:%d,max:%d", (int) value, conn->limits->connectionsMax); httpDestroyConn(conn); return 0; } if (mprGetHashLength(http->addresses) > conn->limits->clientMax) { httpTrace(conn, "connection.accept.error", "error", "msg:'Too many concurrent clients',active:%d,max:%d", mprGetHashLength(http->addresses), conn->limits->clientMax); httpDestroyConn(conn); return 0; } address = conn->address; if (address && address->banUntil) { if (address->banUntil < http->now) { httpTrace(conn, "monitor.ban.stop", "context", "client:'%s'", conn->ip); address->banUntil = 0; } else { if (address->banStatus) { httpError(conn, HTTP_CLOSE | address->banStatus, "Connection refused, client banned: %s", address->banMsg ? address->banMsg : ""); } else { httpDestroyConn(conn); return 0; } } } if (endpoint->ssl) { if (mprUpgradeSocket(sock, endpoint->ssl, 0) < 0) { httpDisconnect(conn); httpTrace(conn, "connection.upgrade.error", "error", "msg:'Cannot upgrade socket. %s'", sock->errorMsg); httpMonitorEvent(conn, HTTP_COUNTER_SSL_ERRORS, 1); httpDestroyConn(conn); return 0; } } assert(conn->state == HTTP_STATE_BEGIN); httpSetState(conn, HTTP_STATE_CONNECTED); httpTrace(conn, "connection.accept.new", "context", "peer:'%s',endpoint:'%s:%d'", conn->ip, sock->acceptIp, sock->acceptPort); event->mask = MPR_READABLE; event->timestamp = conn->http->now; (conn->ioCallback)(conn, event); return conn; }
/* Accept a new client connection on a new socket. If multithreaded, this will come in on a worker thread dedicated to this connection. This is called from the listen wait handler. */ HttpConn *httpAcceptConn(HttpEndpoint *endpoint, MprEvent *event) { HttpConn *conn; MprSocket *sock; MprDispatcher *dispatcher; MprEvent e; int level; mprAssert(endpoint); mprAssert(event); /* This will block in sync mode until a connection arrives */ if ((sock = mprAcceptSocket(endpoint->sock)) == 0) { if (endpoint->sock->handler) { mprEnableSocketEvents(endpoint->sock, MPR_READABLE); } return 0; } if (endpoint->ssl) { if (mprUpgradeSocket(sock, endpoint->ssl, 1) < 0) { mprCloseSocket(sock, 0); return 0; } } if (endpoint->sock->handler) { /* Re-enable events on the listen socket */ mprEnableSocketEvents(endpoint->sock, MPR_READABLE); } dispatcher = event->dispatcher; if (mprShouldDenyNewRequests()) { mprCloseSocket(sock, 0); return 0; } if ((conn = httpCreateConn(endpoint->http, endpoint, dispatcher)) == 0) { mprCloseSocket(sock, 0); return 0; } conn->notifier = endpoint->notifier; conn->async = endpoint->async; conn->endpoint = endpoint; conn->sock = sock; conn->port = sock->port; conn->ip = sclone(sock->ip); conn->secure = (endpoint->ssl != 0); if (!httpValidateLimits(endpoint, HTTP_VALIDATE_OPEN_CONN, conn)) { conn->endpoint = 0; httpDestroyConn(conn); return 0; } mprAssert(conn->state == HTTP_STATE_BEGIN); httpSetState(conn, HTTP_STATE_CONNECTED); if ((level = httpShouldTrace(conn, HTTP_TRACE_RX, HTTP_TRACE_CONN, NULL)) >= 0) { mprLog(level, "### Incoming connection from %s:%d to %s:%d %s", conn->ip, conn->port, sock->acceptIp, sock->acceptPort, conn->secure ? "(secure)" : ""); } e.mask = MPR_READABLE; e.timestamp = conn->http->now; (conn->ioCallback)(conn, &e); return conn; }
static HttpConn *openConnection(HttpConn *conn, cchar *url, struct MprSsl *ssl) { Http *http; HttpUri *uri; MprSocket *sp; char *ip; int port, rc, level; mprAssert(conn); http = conn->http; uri = httpCreateUri(url, HTTP_COMPLETE_URI); conn->tx->parsedUri = uri; if (*url == '/') { ip = (http->proxyHost) ? http->proxyHost : http->defaultClientHost; port = (http->proxyHost) ? http->proxyPort : http->defaultClientPort; } else { ip = (http->proxyHost) ? http->proxyHost : uri->host; port = (http->proxyHost) ? http->proxyPort : uri->port; } if (port == 0) { port = (uri->secure) ? 443 : 80; } if (conn && conn->sock) { if (--conn->keepAliveCount < 0 || port != conn->port || strcmp(ip, conn->ip) != 0 || uri->secure != (conn->sock->ssl != 0) || conn->sock->ssl != ssl) { httpCloseConn(conn); } else { mprLog(4, "Http: reusing keep-alive socket on: %s:%d", ip, port); } } if (conn->sock) { return conn; } if ((sp = mprCreateSocket()) == 0) { httpError(conn, HTTP_CODE_COMMS_ERROR, "Can't create socket for %s", url); return 0; } if ((rc = mprConnectSocket(sp, ip, port, 0)) < 0) { httpError(conn, HTTP_CODE_COMMS_ERROR, "Can't open socket on %s:%d", ip, port); return 0; } #if BIT_PACK_SSL /* Must be done even if using keep alive for repeat SSL requests */ if (uri->secure) { if (ssl == 0) { ssl = mprCreateSsl(); } if (mprUpgradeSocket(sp, ssl, 0) < 0) { conn->errorMsg = sp->errorMsg; return 0; } } #endif conn->sock = sp; conn->ip = sclone(ip); conn->port = port; conn->secure = uri->secure; conn->keepAliveCount = (conn->limits->keepAliveMax) ? conn->limits->keepAliveMax : -1; if ((level = httpShouldTrace(conn, HTTP_TRACE_RX, HTTP_TRACE_CONN, NULL)) >= 0) { mprLog(level, "### Outgoing connection from %s:%d to %s:%d", conn->ip, conn->port, conn->sock->ip, conn->sock->port); } return conn; }