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);
 

Attachment: nonblocking.patch.gz
Description: GNU Zip compressed data

Reply via email to