Hi, Stipe. Stipe Tolj wrote:
Hi Vjacheslav,
thanks a lot for the submission of the patch.
Could you please be so kind to use the unified diff format which is
invoked with the -u switch, like
$ diff -u <oldfile> <newfile>
and attach the output to the mail, please no inline. Could you resend
it that way and I will commit it to cvs today. Thanks in advance.
I don't use inline, may be mail program do it for me. So I send 2 attachments, diff and gzipped diff.
Stipe [EMAIL PROTECTED] -------------------------------------------------------------------
-- Vjacheslav Chekushin mailto:sck@;lmt.lv Latvian Mobile Phone Company http://www.lmt.lv
diff -ubr --exclude=CVS gwlib/conn.c /home/wapgw/kannel/develcvs2/gateway/gwlib/conn.c --- gwlib/conn.c Tue Jun 11 23:59:52 2002 +++ /home/wapgw/kannel/develcvs2/gateway/gwlib/conn.c Tue Nov 12 09:23:07 2002 @@ -62,6 +62,9 @@ /* fd value is read-only and is not locked */ int fd; + /* socket state */ + enum {yes,no} connected; + /* Protected by outlock */ Octstr *outbuf; long outbufpos; /* start of unwritten data in outbuf */ @@ -460,6 +463,51 @@ return conn_open_tcp_with_port(host, port, 0, our_host); } +Connection *conn_open_tcp_nb(Octstr *host, int port, Octstr *our_host) +{ + return conn_open_tcp_nb_with_port(host, port, 0, our_host); +} + +Connection *conn_open_tcp_nb_with_port(Octstr *host, int port, int our_port, + Octstr *our_host) +{ + int sockfd; + int done = -1; + Connection *c; + + sockfd = tcpip_connect_nb_to_server_with_port(octstr_get_cstr(host), port, + our_port, our_host == NULL ? + NULL : octstr_get_cstr(our_host), +&done); + if (sockfd < 0) + return NULL; + c = conn_wrap_fd(sockfd, 0); + if (done != 0) { + c->connected = no; + } + return c; +} + +int conn_is_connected(Connection *conn) +{ + if (conn->connected == yes) return 0; + return -1; +} + +int conn_get_connect_result(Connection *conn) +{ + int err,len; + len = sizeof(len); + if (getsockopt(conn->fd, SOL_SOCKET, SO_ERROR, &err, &len) < 0) { + return -1; + } + + if (err) { + return -1; + } + + conn->connected = yes; + return 0; +} Connection *conn_open_tcp_with_port(Octstr *host, int port, int our_port, Octstr *our_host) @@ -493,6 +541,7 @@ conn->inbufpos = 0; conn->fd = fd; + conn->connected = yes; conn->read_eof = 0; conn->read_error = 0; conn->output_buffering = DEFAULT_OUTPUT_BUFFERING; @@ -746,6 +795,13 @@ return; } + /* Get result of nonblocking connect, before any reads and writes + * we must check result (it must be handled in initial callback) */ + if (conn->connected == no) { + conn->callback(conn, conn->callback_data); + return; + } + /* If unlocked_write manages to write all pending data, it will * tell the fdset to stop listening for POLLOUT. */ if (revents & POLLOUT) { @@ -794,10 +850,16 @@ result = -1; } else { events = 0; + /* For nonconnected socket we must lesten both directions */ + if (conn->connected == yes) { if (conn->read_eof == 0 && conn->read_error == 0) events |= POLLIN; if (unlocked_outbuf_len(conn) > 0) events |= POLLOUT; + } else { + events |= POLLIN; + events |= POLLOUT; + } conn->registered = fdset; conn->callback = callback; diff -ubr --exclude=CVS gwlib/conn.h /home/wapgw/kannel/develcvs2/gateway/gwlib/conn.h --- gwlib/conn.h Thu Aug 8 19:24:43 2002 +++ /home/wapgw/kannel/develcvs2/gateway/gwlib/conn.h Tue Nov 12 09:23:07 2002 @@ -75,6 +75,23 @@ Connection *conn_open_tcp_with_port(Octstr *host, int port, int our_port, Octstr *our_host); +/* Open a TCP/IP connection to the given host and port. Return NULL in case of + * error. Overwise return new Connection. */ +Connection *conn_open_tcp_nb(Octstr *host, int port, Octstr *our_host); + +/* As above, but binds our end to 'our_port'. If 'our_port' is 0, uses + * any port like conn_open_tcp. */ +Connection *conn_open_tcp_nb_with_port(Octstr *host, int port, int our_port, + Octstr *our_host); + +/* Returns 0 if socket is connected, -1 overwise */ +int conn_is_connected(Connection *conn); + +/* If socket is in the 'connecting' state, it must be listen by poller. + * After poller returns, connection must be checked for connection + * procedure's result. Return 0 if connection done successfully */ +int conn_get_connect_result(Connection *conn); + /* Create a Connection structure around the given file descriptor. * The file descriptor must not be used for anything else after this; * it must always be accessed via the Connection operations. This diff -ubr --exclude=CVS gwlib/http.c /home/wapgw/kannel/develcvs2/gateway/gwlib/http.c --- gwlib/http.c Thu Oct 17 12:22:39 2002 +++ /home/wapgw/kannel/develcvs2/gateway/gwlib/http.c Tue Nov 12 09:34:33 2002 @@ -550,7 +550,6 @@ "GET", "POST", "HEAD" }; - /* * Information about a server we've connected to. */ @@ -562,6 +561,7 @@ List *request_headers; Octstr *request_body; /* NULL for GET or HEAD, non-NULL for POST */ enum { + connecting, request_not_sent, reading_status, reading_entity, @@ -582,6 +582,8 @@ } HTTPServer; +static int send_request(HTTPServer *trans); + static HTTPServer *server_create(HTTPCaller *caller, int method, Octstr *url, List *headers, Octstr *body, int follow_remaining, Octstr *certkeyfile) @@ -698,7 +700,7 @@ conn = conn_open_ssl(host, port, certkeyfile, our_host); else #endif /* HAVE_LIBSSL */ - conn = conn_open_tcp(host, port, our_host); + conn = conn_open_tcp_nb(host, port, our_host); debug("gwlib.http", 0, "HTTP: Opening connection to `%s:%d' (fd=%d).", octstr_get_cstr(host), port, conn_get_id(conn)); } else { @@ -851,6 +853,8 @@ HTTPServer *trans; int ret; Octstr *h; + int rc; + char buf[128]; trans = data; @@ -861,6 +865,43 @@ while (trans->state != transaction_done) { switch (trans->state) { + case connecting: + debug("gwlib.http", 0, "Get info about connecting socket"); + if (conn_get_connect_result(trans->conn) != 0) { + debug("gwlib.http", 0, "Socket not connected"); + conn_unregister(conn); + goto error; + } + + if (trans->method == HTTP_METHOD_POST) { + /* + * Add a Content-Length header. Override an existing one, if + * necessary. We must have an accurate one in order to use the + * connection for more than a single request. + */ + http_header_remove_all(trans->request_headers, "Content-Length"); + sprintf(buf, "%ld", octstr_len(trans->request_body)); + http_header_add(trans->request_headers, "Content-Length", buf); + } + /* + * ok, this has to be an GET or HEAD request method then, + * if it contains a body, then this is not HTTP conform, so at + * least warn the user + */ + else if (trans->request_body != NULL) { + warning(0, "HTTP: GET or HEAD method request contains body:"); + octstr_dump(trans->request_body, 0); + } + + if ((rc = send_request(trans)) == 0) { + trans->state = reading_status; + conn_register(trans->conn, client_fdset, handle_transaction, + trans); + } else { + list_produce(trans->caller, trans); + } + break; + case reading_status: ret = client_read_status(trans); if (ret < 0) { @@ -1120,84 +1161,110 @@ return 0; } - -/* - * Build and send the HTTP request. Return socket from which the - * response can be read or -1 for error. - */ - -static Connection *send_request(HTTPServer *trans) +static Connection *get_connection(HTTPServer *trans) { - Octstr *path, *request; + Octstr *path; Connection *conn; Octstr *host, *our_host = NULL; int port; - path = NULL; - request = NULL; conn = NULL; + path = NULL; /* May not be NULL if we're retrying this transaction. */ octstr_destroy(trans->host); trans->host = NULL; - if(trans->request_headers == NULL) - trans->request_headers = http_create_empty_headers(); - if (parse_url(trans->url, &trans->host, &trans->port, &path, &trans->ssl, &trans->username, &trans->password) == -1) goto error; - if (trans->username != NULL) - http_add_basic_auth(trans->request_headers, trans->username, - trans->password); + + if (proxy_used_for_host(trans->host)) { - proxy_add_authentication(trans->request_headers); - request = build_request(http_method2name(trans->method), - trans->url, trans->host, trans->port, - trans->request_headers, trans->request_body); host = proxy_hostname; port = proxy_port; } else { - request = build_request(http_method2name(trans->method), path, trans->host, - trans->port, trans->request_headers, - trans->request_body); host = trans->host; port = trans->port; } if (trans->retrying) { #ifdef HAVE_LIBSSL - if (trans->ssl) - conn = conn_open_ssl(host, port, trans->certkeyfile, our_host); + if (trans->ssl) conn = conn_open_ssl(host, port, trans->certkeyfile, our_host); else #endif /* HAVE_LIBSSL */ - conn = conn_open_tcp(host, port, our_host); + conn = conn_open_tcp_nb(host, port, our_host); debug("gwlib.http", 0, "HTTP: Opening NEW connection to `%s:%d' (fd=%d).", octstr_get_cstr(host), port, conn_get_id(conn)); } else - conn = conn_pool_get(host, port, trans->ssl, trans->certkeyfile, our_host); + conn = conn_pool_get(host, port, trans->ssl, trans->certkeyfile, + our_host); if (conn == NULL) goto error; + octstr_destroy(path); + + return conn; + + error: + conn_destroy(conn); + octstr_destroy(path); + error(0, "Couldn't send request to <%s>", octstr_get_cstr(trans->url)); + return NULL; +} + +/* + * Build and send the HTTP request. Return socket from which the + * response can be read or -1 for error. + */ + +static int send_request(HTTPServer *trans) +{ + Octstr *path, *request; + + path = NULL; + request = NULL; + + if (parse_url(trans->url, &trans->host, &trans->port, &path, &trans->ssl, + &trans->username, &trans->password) == -1) + goto error; + + if (trans->username != NULL) + http_add_basic_auth(trans->request_headers, trans->username, + trans->password); + + if (proxy_used_for_host(trans->host)) { + proxy_add_authentication(trans->request_headers); + request = build_request(http_method2name(trans->method), + trans->url, trans->host, trans->port, + trans->request_headers, + trans->request_body); + } else { + request = build_request(http_method2name(trans->method),path, + trans->host, trans->port, + trans->request_headers, + trans->request_body); + } + debug("wsp.http", 0, "HTTP: Sending request:"); octstr_dump(request, 0); - if (conn_write(conn, request) == -1) + if (conn_write(trans->conn, request) == -1) goto error; octstr_destroy(path); octstr_destroy(request); - return conn; + return 0; -error: - conn_destroy(conn); + error: + conn_destroy(trans->conn); + trans->conn = NULL; octstr_destroy(path); octstr_destroy(request); error(0, "Couldn't send request to <%s>", octstr_get_cstr(trans->url)); - return NULL; + return -1; } - /* * This thread starts the transaction: it connects to the server and sends * the request. It then sends the transaction to the read_response_thread @@ -1207,6 +1274,7 @@ { HTTPServer *trans; char buf[128]; + int rc; while (run_status == running) { trans = list_consume(pending_requests); @@ -1215,6 +1283,14 @@ gw_assert(trans->state == request_not_sent); + trans->conn = get_connection(trans); + + if (trans->conn == NULL) + list_produce(trans->caller, trans); + else { + if (conn_is_connected(trans->conn) == 0) { + debug("gwlib.http", 0, "Socket connected at once"); + if (trans->method == HTTP_METHOD_POST) { /* * Add a Content-Length header. Override an existing one, if @@ -1234,14 +1310,21 @@ warning(0, "HTTP: GET or HEAD method request contains body:"); octstr_dump(trans->request_body, 0); } - - trans->conn = send_request(trans); - if (trans->conn == NULL) - list_produce(trans->caller, trans); - else { + if ((rc = send_request(trans)) == 0) { trans->state = reading_status; + conn_register(trans->conn, client_fdset, handle_transaction, + trans); + } else { + list_produce(trans->caller, trans); + } + + } else { /* Socket not connected, wait for connection */ + debug("gwlib.http", 0, "Socket connecting"); + trans->state = connecting; conn_register(trans->conn, client_fdset, handle_transaction, trans); } + + } } } diff -ubr --exclude=CVS gwlib/socket.c /home/wapgw/kannel/develcvs2/gateway/gwlib/socket.c --- gwlib/socket.c Thu May 2 17:44:54 2002 +++ /home/wapgw/kannel/develcvs2/gateway/gwlib/socket.c Tue Nov 12 09:23:07 2002 @@ -160,6 +160,92 @@ return -1; } +int tcpip_connect_nb_to_server(char *hostname, int port, const char *interface_name, +int *done) +{ + return tcpip_connect_nb_to_server_with_port(hostname, port, 0, interface_name, +done); +} + +int tcpip_connect_nb_to_server_with_port(char *hostname, int port, int our_port, +const char *interface_name, int *done) +{ + struct sockaddr_in addr; + struct sockaddr_in o_addr; + struct hostent hostinfo; + struct hostent o_hostinfo; + int s; + int flags,rc; + + *done = 1; + + s = socket(PF_INET, SOCK_STREAM, 0); + if (s == -1) { + error(errno, "Couldn't create new socket."); + goto error; + } + + if (gw_gethostbyname(&hostinfo, hostname) == -1) { + error(errno, "gethostbyname failed"); + goto error; + } + + addr = empty_sockaddr_in; + addr.sin_family = AF_INET; + addr.sin_port = htons(port); + addr.sin_addr = *(struct in_addr *) hostinfo.h_addr; + + if (our_port > 0 || (interface_name != NULL && strcmp(interface_name, "*") != 0)) { + int reuse; + + o_addr = empty_sockaddr_in; + o_addr.sin_family = AF_INET; + o_addr.sin_port = htons(our_port); + if (interface_name == NULL || strcmp(interface_name, "*") == 0) + o_addr.sin_addr.s_addr = htonl(INADDR_ANY); + else { + if (gw_gethostbyname(&o_hostinfo, interface_name) == -1) { + error(errno, "gethostbyname failed"); + goto error; + } + o_addr.sin_addr = *(struct in_addr *) o_hostinfo.h_addr; + } + + reuse = 1; + if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *) &reuse, + sizeof(reuse)) == -1) { + error(errno, "setsockopt failed before bind"); + goto error; + } + if (bind(s, (struct sockaddr *) &o_addr, sizeof(o_addr)) == -1) { + error(errno, "bind to local port %d failed", our_port); + goto error; + } + } + + flags = fcntl(s, F_GETFL, 0); + fcntl(s, F_SETFL, flags | O_NONBLOCK); + + if ((rc = connect(s, (struct sockaddr *) &addr, sizeof(addr))) < 0) { + if (errno != EINPROGRESS) { + error(errno, "nonblocking connect failed"); + goto error; + } + } + + /* May be connected immediatly + * (if we connecting to localhost for example) */ + if (rc == 0) { + *done = 0; + } + + return s; + + error: + error(0, "error connecting to server `%s' at port `%d'", + hostname, port); + if (s >= 0) + close(s); + return -1; +} + int write_to_socket(int socket, char *str) { diff -ubr --exclude=CVS gwlib/socket.h /home/wapgw/kannel/develcvs2/gateway/gwlib/socket.h --- gwlib/socket.h Mon Oct 8 22:43:04 2001 +++ /home/wapgw/kannel/develcvs2/gateway/gwlib/socket.h Tue Nov 12 09:23:07 2002 @@ -38,6 +38,15 @@ int tcpip_connect_to_server_with_port(char *hostname, int port, int our_port, const char *interface_name); +/* Open a client socket in nonblocking mode, done is 0 if socket + connected immediatly, overwise done is 1 */ +int tcpip_connect_nb_to_server(char *hostname, int port, const char *interface_name, + int *done); + +/* As above, but binds our end to 'our_port' */ +int tcpip_connect_nb_to_server_with_port(char *hostname, int port, int our_port, + const char *interface_name, int *done); + /* Write string to socket. */ int write_to_socket(int socket, char *str);
nonblocking.patch.gz
Description: GNU Zip compressed data