bf49bb9e1ea759942325f34fc8736523c2f3055e
[people/xl0/gpxe.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         /* Hand off to application */
160         if ( app->op->acked )
161                 app->op->acked ( app, len );
162 }
163
164 /**
165  * Receive new data
166  *
167  * @v conn              Stream connection
168  * @v data              Data
169  * @v len               Length of data
170  */
171 void stream_newdata ( struct stream_connection *conn, 
172                       void *data, size_t len ) {
173         struct stream_application *app = conn->app;
174
175         DBGC2 ( app, "Stream %p received %zd bytes\n", app, len );
176
177         /* Check connection actually exists */
178         if ( ! app ) {
179                 DBGC ( conn, "Stream connection %p has no application\n",
180                        conn );
181                 return;
182         }
183
184         /* Hand off to application */
185         if ( app->op->newdata )
186                 app->op->newdata ( app, data, len );
187 }
188
189 /**
190  * Bind to local address
191  *
192  * @v app               Stream application
193  * @v local             Local address
194  * @ret rc              Return status code
195  */
196 int stream_bind ( struct stream_application *app, struct sockaddr *local ) {
197         struct stream_connection *conn = app->conn;
198         int rc;
199
200         DBGC2 ( app, "Stream %p binding\n", app );
201
202         /* Check connection actually exists */
203         if ( ! conn ) {
204                 DBGC ( app, "Stream %p has no connection\n", app );
205                 return -ENOTCONN;
206         }
207
208         /* Hand off to connection */
209         if ( ! conn->op->bind )
210                 return -ENOTSUP;
211         if ( ( rc = conn->op->bind ( conn, local ) ) != 0 ) {
212                 DBGC ( app, "Stream %p failed to bind: %s\n",
213                        app, strerror ( rc ) );
214                 return rc;
215         }
216
217         return 0;
218 }
219
220 /**
221  * Connect to remote address
222  *
223  * @v app               Stream application
224  * @v peer              Remote address
225  * @ret rc              Return status code
226  */
227 int stream_connect ( struct stream_application *app, struct sockaddr *peer ) {
228         struct stream_connection *conn = app->conn;
229         int rc;
230
231         DBGC2 ( app, "Stream %p connecting\n", app );
232
233         /* Check connection actually exists */
234         if ( ! conn ) {
235                 DBGC ( app, "Stream %p has no connection\n", app );
236                 return -ENOTCONN;
237         }
238
239         /* Hand off to connection */
240         if ( ! conn->op->connect )
241                 return -ENOTSUP;
242         if ( ( rc = conn->op->connect ( conn, peer ) ) != 0 ) {
243                 DBGC ( app, "Stream %p failed to connect: %s\n",
244                        app, strerror ( rc ) );
245                 return rc;
246         }
247
248         return 0;
249 }
250
251 /**
252  * Close connection
253  *
254  * @v app               Stream application
255  */
256 void stream_close ( struct stream_application *app ) {
257         struct stream_connection *conn = app->conn;
258
259         DBGC2 ( app, "Stream %p closing\n", app );
260
261         /* Check connection actually exists */
262         if ( ! conn ) {
263                 /* Not an error; don't display a debug message */
264                 return;
265         }
266
267         /* Disassociate application from connection */
268         stream_disassociate ( app, conn );
269
270         /* Hand off to connection */
271         if ( ! conn->op->close )
272                 return;
273         conn->op->close ( conn );
274 }
275
276 /**
277  * Send data via connection
278  *
279  * @v app               Stream application
280  * @v data              Data to send
281  * @v len               Length of data
282  * @ret rc              Return status code
283  *
284  * This method should be called only in the context of an
285  * application's senddata() method.
286  */
287 int stream_send ( struct stream_application *app,
288                   const void *data, size_t len ) {
289         struct stream_connection *conn = app->conn;
290         int rc;
291
292         DBGC2 ( app, "Stream %p sending %zd bytes\n", app, len );
293
294         /* Check connection actually exists */
295         if ( ! conn ) {
296                 DBGC ( app, "Stream %p has no connection\n", app );
297                 return -ENOTCONN;
298         }
299
300         /* Hand off to connection */
301         if ( ! conn->op->send )
302                 return -ENOTSUP;
303         if ( ( rc = conn->op->send ( conn, data, len ) ) != 0 ) {
304                 DBGC ( app, "Stream %p failed to send %zd bytes: %s\n",
305                        app, len, strerror ( rc ) );
306                 return rc;
307         }
308
309         return 0;
310 }
311
312 /**
313  * Notify connection that data is available to send
314  *
315  * @v app               Stream application
316  * @ret rc              Return status code
317  */
318 int stream_kick ( struct stream_application *app ) {
319                 struct stream_connection *conn = app->conn;
320         int rc;
321
322         DBGC2 ( app, "Stream %p kicking connection\n", app );
323
324         /* Check connection actually exists */
325         if ( ! conn ) {
326                 DBGC ( app, "Stream %p has no connection\n", app );
327                 return -ENOTCONN;
328         }
329
330         /* Hand off to connection */
331         if ( ! conn->op->send )
332                 return -ENOTSUP;
333         if ( ( rc = conn->op->kick ( conn ) ) != 0 ) {
334                 DBGC ( app, "Stream %p failed to kick connection: %s\n",
335                        app, strerror ( rc ) );
336                 return rc;
337         }
338
339         return 0;
340 }