starting to use stream in fs
[oweals/gnunet.git] / src / fs / gnunet-service-fs_stream.c
1 /*
2      This file is part of GNUnet.
3      (C) 2012 Christian Grothoff (and other contributing authors)
4
5      GNUnet is free software; you can redistribute it and/or modify
6      it under the terms of the GNU General Public License as published
7      by the Free Software Foundation; either version 3, or (at your
8      option) any later version.
9
10      GNUnet is distributed in the hope that it will be useful, but
11      WITHOUT ANY WARRANTY; without even the implied warranty of
12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13      General Public License for more details.
14
15      You should have received a copy of the GNU General Public License
16      along with GNUnet; see the file COPYING.  If not, write to the
17      Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18      Boston, MA 02111-1307, USA.
19 */
20
21 /**
22  * @file fs/gnunet-service-fs_stream.c
23  * @brief non-anonymous file-transfer
24  * @author Christian Grothoff
25  *
26  * TODO:
27  * - limit # concurrent clients, timeout for read
28  */
29 #include "platform.h"
30 #include "gnunet_constants.h"
31 #include "gnunet_util_lib.h"
32 #include "gnunet_stream_lib.h"
33 #include "gnunet_protocols.h"
34 #include "gnunet_applications.h"
35 #include "gnunet-service-fs.h"
36 #include "gnunet-service-fs_stream.h"
37
38 /**
39  * Information we keep around for each active streaming client.
40  */
41 struct StreamClient
42 {
43   /**
44    * DLL
45    */ 
46   struct StreamClient *next;
47
48   /**
49    * DLL
50    */ 
51   struct StreamClient *prev;
52
53   /**
54    * Socket for communication.
55    */ 
56   struct GNUNET_STREAM_Socket *socket;
57
58   /**
59    * Handle for active read operation, or NULL.
60    */ 
61   struct GNUNET_STREAM_IOReadHandle *rh;
62
63   /**
64    * Handle for active write operation, or NULL.
65    */ 
66   struct GNUNET_STREAM_IOWriteHandle *wh;
67   
68   /**
69    * Size of the last write that was initiated.
70    */ 
71   size_t reply_size;
72
73 };
74
75
76 /**
77  * Listen socket for incoming requests.
78  */
79 static struct GNUNET_STREAM_ListenSocket *listen_socket;
80
81 /**
82  * Head of DLL of stream clients.
83  */ 
84 static struct StreamClient *sc_head;
85
86 /**
87  * Tail of DLL of stream clients.
88  */ 
89 static struct StreamClient *sc_tail;
90
91
92 /**
93  * We're done with a particular client, clean up.
94  *
95  * @param sc client to clean up
96  */
97 static void
98 terminate_stream (struct StreamClient *sc)
99 {
100   if (NULL != sc->rh)
101     GNUNET_STREAM_io_read_cancel (sc->rh);
102   if (NULL != sc->wh)
103     GNUNET_STREAM_io_write_cancel (sc->wh);
104   GNUNET_STREAM_close (sc->socket);
105   GNUNET_CONTAINER_DLL_remove (sc_head,
106                                sc_tail,
107                                sc);
108   GNUNET_free (sc);
109 }
110
111
112 /**
113  * Functions of this signature are called whenever data is available from the
114  * stream.
115  *
116  * @param cls the closure from GNUNET_STREAM_read
117  * @param status the status of the stream at the time this function is called
118  * @param data traffic from the other side
119  * @param size the number of bytes available in data read; will be 0 on timeout 
120  * @return number of bytes of processed from 'data' (any data remaining should be
121  *         given to the next time the read processor is called).
122  */
123 static size_t 
124 process_request (void *cls,
125                  enum GNUNET_STREAM_Status status,
126                  const void *data,
127                  size_t size)
128 {
129   struct StreamClient *sc = cls;
130
131   sc->rh = NULL;
132   switch (status)
133   {
134   case GNUNET_STREAM_OK:
135     // fixme: handle request...
136     break;
137   case GNUNET_STREAM_TIMEOUT:
138   case GNUNET_STREAM_SHUTDOWN:
139   case GNUNET_STREAM_SYSERR:
140   case GNUNET_STREAM_BROKEN:
141     terminate_stream (sc);
142     return size;
143   default:
144     GNUNET_break (0);
145     return size;
146   }
147   sc->rh = GNUNET_STREAM_read (sc->socket,
148                                GNUNET_TIME_UNIT_FOREVER_REL,
149                                &process_request,
150                                sc);
151   return size;
152 }
153
154
155 /**
156  * Functions of this type are called upon new stream connection from other peers
157  * or upon binding error which happen when the app_port given in
158  * GNUNET_STREAM_listen() is already taken.
159  *
160  * @param cls the closure from GNUNET_STREAM_listen
161  * @param socket the socket representing the stream; NULL on binding error
162  * @param initiator the identity of the peer who wants to establish a stream
163  *            with us; NULL on binding error
164  * @return GNUNET_OK to keep the socket open, GNUNET_SYSERR to close the
165  *             stream (the socket will be invalid after the call)
166  */
167 static int 
168 accept_cb (void *cls,
169            struct GNUNET_STREAM_Socket *socket,
170            const struct GNUNET_PeerIdentity *initiator)
171 {
172   struct StreamClient *sc;
173
174   if (NULL == socket)
175     return GNUNET_SYSERR;
176   sc = GNUNET_malloc (sizeof (struct StreamClient));
177   sc->socket = socket;
178   sc->rh = GNUNET_STREAM_read (sc->socket,
179                                GNUNET_TIME_UNIT_FOREVER_REL,
180                                &process_request,
181                                sc);
182   GNUNET_CONTAINER_DLL_insert (sc_head,
183                                sc_tail,
184                                sc);
185   return GNUNET_OK;
186 }
187
188
189 /**
190  * Initialize subsystem for non-anonymous file-sharing.
191  */
192 void
193 GSF_stream_start ()
194 {
195   listen_socket = GNUNET_STREAM_listen (GSF_cfg,
196                                         GNUNET_APPLICATION_TYPE_FS_BLOCK_TRANSFER,
197                                         &accept_cb, NULL,
198                                         GNUNET_STREAM_OPTION_END);
199 }
200
201
202 /**
203  * Shutdown subsystem for non-anonymous file-sharing.
204  */
205 void
206 GSF_stream_stop ()
207 {
208   struct StreamClient *sc;
209
210   while (NULL != (sc = sc_head))
211     terminate_stream (sc);
212   if (NULL != listen_socket)
213   {
214     GNUNET_STREAM_listen_close (listen_socket);
215     listen_socket = NULL;
216   }
217 }
218
219 /* end of gnunet-service-fs_stream.c */