Module: sip-router
Branch: andrei/send_flags
Commit: 340ce466abb2938ba9db1d3cb1d8b10819c1e2aa
URL:    
http://git.sip-router.org/cgi-bin/gitweb.cgi/sip-router/?a=commit;h=340ce466abb2938ba9db1d3cb1d8b10819c1e2aa

Author: Andrei Pelinescu-Onciul <[email protected]>
Committer: Andrei Pelinescu-Onciul <[email protected]>
Date:   Tue Sep 15 17:45:41 2009 +0200

tcp: send_flags support

Support for SND_F_FORCE_CON_REUSE and SND_F_CON_CLOSE added to the
tcp code.

---

 tcp_conn.h |    7 ++++-
 tcp_main.c |   85 ++++++++++++++++++++++++++++++++++++++++++++++++------------
 2 files changed, 74 insertions(+), 18 deletions(-)

diff --git a/tcp_conn.h b/tcp_conn.h
index 9db6308..5338734 100644
--- a/tcp_conn.h
+++ b/tcp_conn.h
@@ -170,7 +170,8 @@ struct tcp_connection{
        struct tcp_req req; /* request data */
        atomic_t refcnt;
        enum sip_protos type; /* PROTO_TCP or a protocol over it, e.g. TLS */
-       int flags; /* connection related flags */
+       unsigned short flags; /* connection related flags */
+       unsigned short send_flags; /* special send flags */
        enum tcp_conn_states state; /* connection state */
        void* extra_data; /* extra data associated to the connection, 0 for 
tcp*/
        struct timer_ln timer;
@@ -190,6 +191,10 @@ struct tcp_connection{
 
 /* helper macros */
 
+#define tcpconn_set_send_flags(c, snd_flags) ((c)->send_flags|=(snd_flags))
+
+#define tcpconn_close_after_send(c)    ((c)->send_flags & SND_F_CON_CLOSE)
+
 #define TCP_RCV_INFO(c) (&(c)->rcv)
 
 #define TCP_RCV_LADDR(r) (&((r).dst_ip))
diff --git a/tcp_main.c b/tcp_main.c
index c238b2e..a72e3cc 100644
--- a/tcp_main.c
+++ b/tcp_main.c
@@ -100,7 +100,9 @@
  *  2009-02-26  direct blacklist support (andrei)
  *  2009-03-20  s/wq_timeout/send_timeout ; send_timeout is now in ticks
  *              (andrei)
- * 2009-04-09  tcp ev and tcp stats macros added (andrei)
+ *  2009-04-09  tcp ev and tcp stats macros added (andrei)
+ *  2009-09-15  support for force connection reuse and close after send
+ *               send flags (andrei)
  */
 
 
@@ -1762,18 +1764,24 @@ int tcp_send(struct dest_info* dst, union 
sockaddr_union* from,
                        if (likely(port)){
                                /* try again w/o id */
                                c=tcpconn_get(0, &ip, port, from, con_lifetime);
-                               goto no_id;
                        }else{
                                LOG(L_ERR, "ERROR: tcp_send: id %d not found, 
dropping\n",
                                                dst->id);
                                return -1;
                        }
-               }else goto get_fd;
+               }
        }
-no_id:
-               if (unlikely(c==0)){
+/* no_id: */
+               if (unlikely((c==0) || tcpconn_close_after_send(c))){
+                       if (unlikely(c)){
+                               /* can't use c if it's marked as 
close-after-send  =>
+                                  release it and try opening new one */
+                               tcpconn_chld_put(c); /* release c (dec refcnt & 
free on 0) */
+                               c=0;
+                       }
                        /* check if connect() is disabled */
-                       if (cfg_get(tcp, tcp_cfg, no_connect))
+                       if (unlikely((dst->send_flags & SND_F_FORCE_CON_REUSE) 
||
+                                                       cfg_get(tcp, tcp_cfg, 
no_connect)))
                                return -1;
                        DBG("tcp_send: no open tcp connection found, opening 
new one\n");
                        /* create tcp connection */
@@ -1814,6 +1822,7 @@ no_id:
                                        return -1;
                                }
                                c->flags|=F_CONN_PENDING|F_CONN_FD_CLOSED;
+                               tcpconn_set_send_flags(c, dst->send_flags);
                                atomic_set(&c->refcnt, 2); /* ref from here and 
from main hash
                                                                                
         table */
                                /* add it to id hash and aliases */
@@ -1918,6 +1927,14 @@ no_id:
                                }
                                LOG(L_INFO, "tcp_send: quick connect for %p\n", 
c);
                                TCP_STATS_ESTABLISHED(S_CONN_CONNECT);
+                               if (unlikely(dst->send_flags & 
SND_F_CON_CLOSE)){
+                                       /* if close-after-send requested, don't 
bother
+                                          sending the fd back to tcp_main, try 
closing it
+                                          immediately (no other tcp_send 
should use it,
+                                          because it is marked as 
close-after-send before
+                                          being added to the hash */
+                                       goto conn_wait_close;
+                               }
                                c->state=S_CONN_OK;
                                /* send to tcp_main */
                                response[0]=(long)c;
@@ -1938,6 +1955,7 @@ no_id:
                                                                su2a(&dst->to, 
sizeof(dst->to)));
                                return -1;
                        }
+                       tcpconn_set_send_flags(c, dst->send_flags);
                        if (likely(c->state==S_CONN_OK))
                                TCP_STATS_ESTABLISHED(S_CONN_CONNECT);
                        atomic_set(&c->refcnt, 2); /* ref. from here and it 
will also
@@ -1962,7 +1980,7 @@ no_id:
                        }
                        goto send_it;
                }
-get_fd:
+/* get_fd: */
 #ifdef TCP_ASYNC
                /* if data is already queued, we don't need the fd any more */
                if (unlikely(cfg_get(tcp, tcp_cfg, async) &&
@@ -2048,6 +2066,8 @@ get_fd:
 send_it:
        DBG("tcp_send: sending...\n");
        lock_get(&c->write_lock);
+       /* update connection send flags with the current ones */
+       tcpconn_set_send_flags(c, dst->send_flags);
 #ifdef TCP_ASYNC
        if (likely(cfg_get(tcp, tcp_cfg, async))){
                if (_wbufq_non_empty(c)
@@ -2203,6 +2223,31 @@ error:
                        TCP_STATS_ESTABLISHED(c->state);
                        c->state=S_CONN_OK;
        }
+       if (unlikely(dst->send_flags & SND_F_CON_CLOSE)){
+               /* close after write => send EOF request to tcp_main */
+               c->state=S_CONN_BAD;
+               c->timeout=get_ticks_raw();
+               /* tell "main" it should drop this*/
+               response[0]=(long)c;
+               response[1]=CONN_EOF;
+               if (send_all(unix_tcp_sock, response, sizeof(response))<=0){
+                       LOG(L_CRIT, "BUG: tcp_send: error return failed 
(write):%s (%d)\n",
+                                       strerror(errno), errno);
+                       tcpconn_chld_put(c); /* deref. it manually */
+                       n=-1;
+               }
+               /* CONN_EOF will auto-dec refcnt => we must not call 
tcpconn_put 
+                * if it succeeds */
+#ifdef TCP_FD_CACHE
+               if (unlikely(fd_cache_e)){
+                       tcp_fd_cache_rm(fd_cache_e);
+                       fd_cache_e=0;
+                       close(fd);
+               }else
+#endif /* TCP_FD_CACHE */
+               if (do_close_fd) close(fd);
+               goto end_no_conn;
+       }
 end:
 #ifdef TCP_FD_CACHE
        if (unlikely((fd_cache_e==0) && use_fd_cache)){
@@ -2216,11 +2261,14 @@ end_no_conn:
        return n;
 #ifdef TCP_CONNECT_WAIT
 conn_wait_error:
-       /* connect or send failed on newly created connection which was not
-        * yet sent to tcp_main (but was already hashed) => don't send to main,
-        * unhash and destroy directly (if refcnt>2 it will be destroyed when 
the 
-        * last sender releases the connection (tcpconn_chld_put(c))) or when
-        * tcp_main receives a CONN_ERROR it*/
+       n=-1;
+conn_wait_close:
+       /* connect or send failed or immediate close-after-send was requested on
+        * newly created connection which was not yet sent to tcp_main (but was
+        * already hashed) => don't send to main, unhash and destroy directly
+        * (if refcnt>2 it will be destroyed when the last sender releases the
+        * connection (tcpconn_chld_put(c))) or when tcp_main receives a
+        * CONN_ERROR it*/
        c->state=S_CONN_BAD;
        TCPCONN_LOCK;
                if (c->flags & F_CONN_HASHED){
@@ -2234,7 +2282,7 @@ conn_wait_error:
                        TCPCONN_UNLOCK;
        /* dec refcnt -> mark it for destruction */
        tcpconn_chld_put(c);
-       return -1;
+       return n;
 #endif /* TCP_CONNET_WAIT */
 }
 
@@ -3025,11 +3073,12 @@ inline static int handle_ser_child(struct 
process_table* p, int fd_i)
                        LOG(L_ERR, "handle_ser_child: ERROR: received CON_ERROR 
for %p"
                                        " (id %d), refcnt %d\n", 
                                        tcpconn, tcpconn->id, 
atomic_get(&tcpconn->refcnt));
+               case CONN_EOF: /* forced EOF after full send, due to send flags 
*/
 #ifdef TCP_CONNECT_WAIT
                        /* if the connection is pending => it might be on the 
way of
                         * reaching tcp_main (e.g. CONN_NEW_COMPLETE or 
                         *  CONN_NEW_PENDING_WRITE) =>  it cannot be destroyed 
here */
-                       if ( !(tcpconn->flags & F_CONN_PENDING) && 
+                       if ( !(tcpconn->flags & F_CONN_PENDING) &&
                                        tcpconn_try_unhash(tcpconn) )
                                tcpconn_put(tcpconn);
 #else /* ! TCP_CONNECT_WAIT */
@@ -3155,7 +3204,7 @@ inline static int handle_ser_child(struct process_table* 
p, int fd_i)
                                        }
                                }
                        }else{
-                               LOG(L_WARN, "tcp_main: hanlder_ser_child: 
connection %p"
+                               LOG(L_WARN, "tcp_main: handler_ser_child: 
connection %p"
                                                        " already watched for 
write\n", tcpconn);
                        }
                        break;
@@ -3466,8 +3515,10 @@ inline static int handle_tcpconn_ev(struct 
tcp_connection* tcpconn, short ev,
        empty_q=0; /* warning fix */
        if (unlikely((ev & (POLLOUT|POLLERR|POLLHUP)) &&
                                        (tcpconn->flags & F_CONN_WRITE_W))){
-               if (unlikely((ev & (POLLERR|POLLHUP)) || 
-                                       (wbufq_run(tcpconn->s, tcpconn, 
&empty_q)<0))){
+               if (unlikely((ev & (POLLERR|POLLHUP)) ||
+                                       (wbufq_run(tcpconn->s, tcpconn, 
&empty_q)<0) ||
+                                       (empty_q && 
tcpconn_close_after_send(tcpconn))
+                       )){
                        if (unlikely(io_watch_del(&io_h, tcpconn->s, fd_i, 
0)<0)){
                                LOG(L_ERR, "ERROR: handle_tcpconn_ev: 
io_watch_del(1) failed:"
                                                        " for %p, fd %d\n", 
tcpconn, tcpconn->s);


_______________________________________________
sr-dev mailing list
[email protected]
http://lists.sip-router.org/cgi-bin/mailman/listinfo/sr-dev

Reply via email to