86fb3066b0f3b92edf3b00febb6e6e9e3745c8fb
[people/indolent/gpxe.git/.git] / src / net / stream.c
1 /*
2  * Copyright (C) 2007 Michael Brown <mbrown@fensystems.co.uk>.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License as
6  * published by the Free Software Foundation; either version 2 of the
7  * License, or any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17  */
18
19 /**
20  * @file
21  *
22  * Stream API
23  */
24
25 #include <stdint.h>
26 #include <string.h>
27 #include <errno.h>
28 #include <assert.h>
29 #include <gpxe/stream.h>
30
31 /**
32  * Associate application with connection
33  *
34  * @v app               Stream application
35  * @v conn              Stream connection
36  */
37 void stream_associate ( struct stream_application *app,
38                         struct stream_connection *conn ) {
39
40         DBGC ( app, "Stream %p associating with connection %p\n", app, conn );
41
42         assert ( conn->app == NULL );
43         assert ( app->conn == NULL );
44         conn->app = app;
45         app->conn = conn;
46 }
47
48 /**
49  * Disassociate application from connection
50  *
51  * @v app               Stream application
52  * @v conn              Stream connection
53  */
54 static void stream_disassociate ( struct stream_application *app,
55                                   struct stream_connection *conn ) {
56
57         DBGC ( app, "Stream %p disassociating from connection %p\n",
58                app, conn );
59
60         assert ( conn->app == app );
61         assert ( app->conn == conn );
62         conn->app = NULL;
63         app->conn = NULL;       
64 }
65
66 /**
67  * Connection established
68  *
69  * @v conn              Stream connection
70  */
71 void stream_connected ( struct stream_connection *conn ) {
72         struct stream_application *app = conn->app;
73
74         DBGC ( app, "Stream %p connected\n", app );
75
76         /* Check connection actually exists */
77         if ( ! app ) {
78                 DBGC ( conn, "Stream connection %p has no application\n",
79                        conn );
80                 return;
81         }
82
83         /* Hand off to application */
84         if ( app->op->connected )
85                 app->op->connected ( app );
86 }
87
88 /**
89  * Connection closed
90  *
91  * @v conn              Stream connection
92  * @v rc                Error code, if any
93  */
94 void stream_closed ( struct stream_connection *conn, int rc ) {
95         struct stream_application *app = conn->app;
96
97         /* Check connection actually exists */
98         if ( ! app ) {
99                 /* Not an error; don't display a debug message */
100                 return;
101         }
102
103         DBGC ( app, "Stream %p closed (%s)\n", app, strerror ( rc ) );
104
105         /* Disassociate application from connection */
106         stream_disassociate ( app, conn );
107
108         /* Hand off to application */
109         if ( app->op->closed )
110                 app->op->closed ( app, rc );
111 }
112
113 /**
114  * Transmit data
115  *
116  * @v conn              Stream connection
117  * @v data              Temporary data buffer
118  * @v len               Length of temporary data buffer
119  */
120 void stream_senddata ( struct stream_connection *conn,
121                        void *data, size_t len ) {
122         struct stream_application *app = conn->app;
123
124         DBGC2 ( app, "Stream %p sending data\n", app );
125
126         /* Check connection actually exists */
127         if ( ! app ) {
128                 DBGC ( conn, "Stream connection %p has no application\n",
129                        conn );
130                 return;
131         }
132
133         /* Hand off to application */
134         if ( app->op->senddata )
135                 app->op->senddata ( app, data, len );
136 }
137
138 /**
139  * Transmitted data acknowledged
140  *
141  * @v conn              Stream connection
142  * @v len               Length of acknowledged data
143  *
144  * @c len must not exceed the outstanding amount of unacknowledged
145  * data.
146  */
147 void stream_acked ( struct stream_connection *conn, size_t len ) {
148         struct stream_application *app = conn->app;
149
150         DBGC2 ( app, "Stream %p had %zd bytes acknowledged\n", app, len );
151
152         /* Check connection actually exists */
153         if ( ! app ) {
154                 DBGC ( conn, "Stream connection %p has no application\n",
155                        conn );
156                 return;
157         }
158
159         /* Ignore zero-length blocks */
160         if ( len == 0 )
161                 return;
162
163         /* Hand off to application */
164         if ( app->op->acked )
165                 app->op->acked ( app, len );
166 }
167
168 /**
169  * Receive new data
170  *
171  * @v conn              Stream connection
172  * @v data              Data
173  * @v len               Length of data
174  */
175 void stream_newdata ( struct stream_connection *conn, 
176                       void *data, size_t len ) {
177         struct stream_application *app = conn->app;
178
179         DBGC2 ( app, "Stream %p received %zd bytes\n", app, len );
180
181         /* Check connection actually exists */
182         if ( ! app ) {
183                 DBGC ( conn, "Stream connection %p has no application\n",
184                        conn );
185                 return;
186         }
187
188         /* Ignore zero-length blocks */
189         if ( len == 0 )
190                 return;
191
192         /* Hand off to application */
193         if ( app->op->newdata )
194                 app->op->newdata ( app, data, len );
195 }
196
197 /**
198  * Bind to local address
199  *
200  * @v app               Stream application
201  * @v local             Local address
202  * @ret rc              Return status code
203  */
204 int stream_bind ( struct stream_application *app, struct sockaddr *local ) {
205         struct stream_connection *conn = app->conn;
206         int rc;
207
208         DBGC2 ( app, "Stream %p binding\n", app );
209
210         /* Check connection actually exists */
211         if ( ! conn ) {
212                 DBGC ( app, "Stream %p has no connection\n", app );
213                 return -ENOTCONN;
214         }
215
216         /* Hand off to connection */
217         if ( ! conn->op->bind )
218                 return -ENOTSUP;
219         if ( ( rc = conn->op->bind ( conn, local ) ) != 0 ) {
220                 DBGC ( app, "Stream %p failed to bind: %s\n",
221                        app, strerror ( rc ) );
222                 return rc;
223         }
224
225         return 0;
226 }
227
228 /**
229  * Connect to remote address
230  *
231  * @v app               Stream application
232  * @v peer              Remote address
233  * @ret rc              Return status code
234  */
235 int stream_connect ( struct stream_application *app, struct sockaddr *peer ) {
236         struct stream_connection *conn = app->conn;
237         int rc;
238
239         DBGC2 ( app, "Stream %p connecting\n", app );
240
241         /* Check connection actually exists */
242         if ( ! conn ) {
243                 DBGC ( app, "Stream %p has no connection\n", app );
244                 return -ENOTCONN;
245         }
246
247         /* Hand off to connection */
248         if ( ! conn->op->connect )
249                 return -ENOTSUP;
250         if ( ( rc = conn->op->connect ( conn, peer ) ) != 0 ) {
251                 DBGC ( app, "Stream %p failed to connect: %s\n",
252                        app, strerror ( rc ) );
253                 return rc;
254         }
255
256         return 0;
257 }
258
259 /**
260  * Close connection
261  *
262  * @v app               Stream application
263  */
264 void stream_close ( struct stream_application *app ) {
265         struct stream_connection *conn = app->conn;
266
267         DBGC2 ( app, "Stream %p closing\n", app );
268
269         /* Check connection actually exists */
270         if ( ! conn ) {
271                 /* Not an error; don't display a debug message */
272                 return;
273         }
274
275         /* Disassociate application from connection */
276         stream_disassociate ( app, conn );
277
278         /* Hand off to connection */
279         if ( ! conn->op->close )
280                 return;
281         conn->op->close ( conn );
282 }
283
284 /**
285  * Send data via connection
286  *
287  * @v app               Stream application
288  * @v data              Data to send
289  * @v len               Length of data
290  * @ret rc              Return status code
291  *
292  * This method should be called only in the context of an
293  * application's senddata() method.
294  */
295 int stream_send ( struct stream_application *app,
296                   const void *data, size_t len ) {
297         struct stream_connection *conn = app->conn;
298         int rc;
299
300         DBGC2 ( app, "Stream %p sending %zd bytes\n", app, len );
301
302         /* Check connection actually exists */
303         if ( ! conn ) {
304                 DBGC ( app, "Stream %p has no connection\n", app );
305                 return -ENOTCONN;
306         }
307
308         /* Ignore zero-length blocks */
309         if ( len == 0 )
310                 return 0;
311
312         /* Hand off to connection */
313         if ( ! conn->op->send )
314                 return -ENOTSUP;
315         if ( ( rc = conn->op->send ( conn, data, len ) ) != 0 ) {
316                 DBGC ( app, "Stream %p failed to send %zd bytes: %s\n",
317                        app, len, strerror ( rc ) );
318                 return rc;
319         }
320
321         return 0;
322 }
323
324 /**
325  * Notify connection that data is available to send
326  *
327  * @v app               Stream application
328  * @ret rc              Return status code
329  */
330 int stream_kick ( struct stream_application *app ) {
331                 struct stream_connection *conn = app->conn;
332         int rc;
333
334         DBGC2 ( app, "Stream %p kicking connection\n", app );
335
336         /* Check connection actually exists */
337         if ( ! conn ) {
338                 DBGC ( app, "Stream %p has no connection\n", app );
339                 return -ENOTCONN;
340         }
341
342         /* Hand off to connection */
343         if ( ! conn->op->send )
344                 return -ENOTSUP;
345         if ( ( rc = conn->op->kick ( conn ) ) != 0 ) {
346                 DBGC ( app, "Stream %p failed to kick connection: %s\n",
347                        app, strerror ( rc ) );
348                 return rc;
349         }
350
351         return 0;
352 }