source: mainline/uspace/srv/net/tl/tcp/sock.c@ 04cd242

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 04cd242 was 04cd242, checked in by Jiri Svoboda <jiri@…>, 14 years ago

Implement socket provider API in tcp module (active side).

  • Property mode set to 100644
File size: 12.2 KB
Line 
1/*
2 * Copyright (c) 2008 Lukas Mejdrech
3 * Copyright (c) 2011 Jiri Svoboda
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * - Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * - Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * - The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30/** @addtogroup tcp
31 * @{
32 */
33
34/**
35 * @file Socket provider
36 */
37
38#include <async.h>
39#include <errno.h>
40#include <io/log.h>
41#include <ipc/socket.h>
42#include <net/modules.h>
43
44#include "sock.h"
45#include "std.h"
46#include "tcp.h"
47#include "tcp_type.h"
48#include "ucall.h"
49
50#define FRAGMENT_SIZE 1024
51
52/** Free ports pool start. */
53#define TCP_FREE_PORTS_START 1025
54
55/** Free ports pool end. */
56#define TCP_FREE_PORTS_END 65535
57
58static int last_used_port;
59static socket_ports_t gsock;
60
61static void tcp_free_sock_data(socket_core_t *sock_core)
62{
63 tcp_sockdata_t *socket;
64
65 socket = (tcp_sockdata_t *)sock_core->specific_data;
66 (void)socket;
67}
68
69static void tcp_sock_notify_data(socket_core_t *sock_core)
70{
71 async_exch_t *exch = async_exchange_begin(sock_core->sess);
72 async_msg_5(exch, NET_SOCKET_RECEIVED, (sysarg_t)sock_core->socket_id,
73 FRAGMENT_SIZE, 0, 0, 1);
74 async_exchange_end(exch);
75}
76
77static void tcp_sock_socket(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
78{
79 tcp_sockdata_t *sock;
80 int sock_id;
81 int rc;
82 ipc_call_t answer;
83
84 log_msg(LVL_DEBUG, "tcp_sock_socket()");
85 sock = calloc(sizeof(tcp_sockdata_t), 1);
86 if (sock == NULL) {
87 async_answer_0(callid, ENOMEM);
88 return;
89 }
90
91 sock->client = client;
92
93 sock_id = SOCKET_GET_SOCKET_ID(call);
94 rc = socket_create(&client->sockets, client->sess, sock, &sock_id);
95 if (rc != EOK) {
96 async_answer_0(callid, rc);
97 return;
98 }
99
100 refresh_answer(&answer, NULL);
101 SOCKET_SET_SOCKET_ID(answer, sock_id);
102
103 SOCKET_SET_DATA_FRAGMENT_SIZE(answer, FRAGMENT_SIZE);
104 SOCKET_SET_HEADER_SIZE(answer, sizeof(tcp_header_t));
105 answer_call(callid, EOK, &answer, 3);
106}
107
108static void tcp_sock_bind(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
109{
110 int rc;
111 struct sockaddr *addr;
112 size_t addr_len;
113 socket_core_t *sock_core;
114 tcp_sockdata_t *socket;
115
116 log_msg(LVL_DEBUG, "tcp_sock_bind()");
117 rc = async_data_write_accept((void **) &addr, false, 0, 0, 0, &addr_len);
118 if (rc != EOK) {
119 async_answer_0(callid, rc);
120 return;
121 }
122
123 rc = socket_bind(&client->sockets, &gsock, SOCKET_GET_SOCKET_ID(call),
124 addr, addr_len, TCP_FREE_PORTS_START, TCP_FREE_PORTS_END,
125 last_used_port);
126 if (rc != EOK) {
127 async_answer_0(callid, rc);
128 return;
129 }
130
131 sock_core = socket_cores_find(&client->sockets, SOCKET_GET_SOCKET_ID(call));
132 if (sock_core != NULL) {
133 socket = (tcp_sockdata_t *)sock_core->specific_data;
134 /* XXX Anything to do? */
135 (void) socket;
136 }
137
138 async_answer_0(callid, ENOTSUP);
139
140 /* Push one fragment notification to client's queue */
141 tcp_sock_notify_data(sock_core);
142}
143
144static void tcp_sock_listen(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
145{
146 int socket_id;
147 int backlog;
148 socket_core_t *sock_core;
149 tcp_sockdata_t *socket;
150
151 log_msg(LVL_DEBUG, "tcp_sock_listen()");
152
153 socket_id = SOCKET_GET_SOCKET_ID(call);
154 backlog = SOCKET_GET_BACKLOG(call);
155
156 if (backlog < 0) {
157 async_answer_0(callid, EINVAL);
158 return;
159 }
160
161 sock_core = socket_cores_find(&client->sockets, socket_id);
162 if (sock_core == NULL) {
163 async_answer_0(callid, ENOTSOCK);
164 return;
165 }
166
167 socket = (tcp_sockdata_t *)sock_core->specific_data;
168 /* XXX Listen */
169 (void)backlog;
170 (void)socket;
171
172 async_answer_0(callid, ENOTSUP);
173
174 /* Push one fragment notification to client's queue */
175 tcp_sock_notify_data(sock_core);
176}
177
178static void tcp_sock_connect(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
179{
180 int rc;
181 struct sockaddr_in *addr;
182 int socket_id;
183 size_t addr_len;
184 socket_core_t *sock_core;
185 tcp_sockdata_t *socket;
186 tcp_error_t trc;
187 tcp_sock_t fsocket;
188 uint16_t lport;
189
190 log_msg(LVL_DEBUG, "tcp_sock_connect()");
191
192 rc = async_data_write_accept((void **) &addr, false, 0, 0, 0, &addr_len);
193 if (rc != EOK || addr_len != sizeof(struct sockaddr_in)) {
194 async_answer_0(callid, rc);
195 return;
196 }
197
198 socket_id = SOCKET_GET_SOCKET_ID(call);
199
200 sock_core = socket_cores_find(&client->sockets, socket_id);
201 if (sock_core == NULL) {
202 async_answer_0(callid, ENOTSOCK);
203 return;
204 }
205
206 socket = (tcp_sockdata_t *)sock_core->specific_data;
207
208 lport = 1024; /* XXX */
209 fsocket.addr.ipv4 = uint32_t_be2host(addr->sin_addr.s_addr);
210 fsocket.port = uint16_t_be2host(addr->sin_port);
211
212 trc = tcp_uc_open(lport, &fsocket, ap_active, &socket->conn);
213
214 switch (trc) {
215 case TCP_EOK:
216 rc = EOK;
217 break;
218 case TCP_ERESET:
219 rc = ECONNREFUSED;
220 break;
221 default:
222 assert(false);
223 }
224
225 async_answer_0(callid, rc);
226}
227
228static void tcp_sock_accept(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
229{
230 ipc_call_t answer;
231 int socket_id;
232 int nsocket_id;
233 socket_core_t *sock_core;
234 tcp_sockdata_t *socket;
235
236 log_msg(LVL_DEBUG, "tcp_sock_accept()");
237
238 socket_id = SOCKET_GET_SOCKET_ID(call);
239 nsocket_id = SOCKET_GET_NEW_SOCKET_ID(call);
240
241 sock_core = socket_cores_find(&client->sockets, socket_id);
242 if (sock_core == NULL) {
243 async_answer_0(callid, ENOTSOCK);
244 return;
245 }
246
247 socket = (tcp_sockdata_t *)sock_core->specific_data;
248 /* XXX Accept */
249 (void) socket;
250 (void) nsocket_id;
251/*
252 refresh_answer(&answer, NULL);
253 SOCKET_SET_DATA_FRAGMENT_SIZE(answer, size)
254 ...
255 async_answer_0(callid, ENOTSUP);*/
256
257 /* TODO */
258 answer_call(callid, ENOTSUP, &answer, 3);
259}
260
261static void tcp_sock_send(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
262{
263 int socket_id;
264 int fragments;
265 int index;
266 socket_core_t *sock_core;
267 tcp_sockdata_t *socket;
268 ipc_call_t answer;
269 ipc_callid_t wcallid;
270 size_t length;
271 uint8_t buffer[FRAGMENT_SIZE];
272 tcp_error_t trc;
273 int rc;
274
275 log_msg(LVL_DEBUG, "******** tcp_sock_send() *******************");
276 socket_id = SOCKET_GET_SOCKET_ID(call);
277 fragments = SOCKET_GET_DATA_FRAGMENTS(call);
278 SOCKET_GET_FLAGS(call);
279
280 sock_core = socket_cores_find(&client->sockets, socket_id);
281 if (sock_core == NULL) {
282 async_answer_0(callid, ENOTSOCK);
283 return;
284 }
285
286 socket = (tcp_sockdata_t *)sock_core->specific_data;
287 if (socket->conn == NULL) {
288 async_answer_0(callid, ENOTCONN);
289 return;
290 }
291
292 for (index = 0; index < fragments; index++) {
293 if (!async_data_write_receive(&wcallid, &length)) {
294 async_answer_0(callid, EINVAL);
295 return;
296 }
297
298 if (length > FRAGMENT_SIZE)
299 length = FRAGMENT_SIZE;
300
301 rc = async_data_write_finalize(wcallid, buffer, length);
302 if (rc != EOK) {
303 async_answer_0(callid, rc);
304 return;
305 }
306
307 trc = tcp_uc_send(socket->conn, buffer, length, 0);
308
309 switch (trc) {
310 case TCP_EOK:
311 rc = EOK;
312 break;
313 case TCP_ENOTEXIST:
314 rc = ENOTCONN;
315 break;
316 case TCP_ECLOSING:
317 rc = ENOTCONN;
318 break;
319 default:
320 assert(false);
321 }
322
323 if (rc != EOK) {
324 async_answer_0(callid, rc);
325 return;
326 }
327 }
328
329 refresh_answer(&answer, NULL);
330 SOCKET_SET_DATA_FRAGMENT_SIZE(answer, FRAGMENT_SIZE);
331 answer_call(callid, EOK, &answer, 2);
332}
333
334static void tcp_sock_sendto(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
335{
336 log_msg(LVL_DEBUG, "tcp_sock_sendto()");
337 async_answer_0(callid, ENOTSUP);
338}
339
340static void tcp_sock_recv(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
341{
342 int socket_id;
343 int flags;
344 size_t length;
345 socket_core_t *sock_core;
346 tcp_sockdata_t *socket;
347 ipc_call_t answer;
348 ipc_callid_t rcallid;
349 uint8_t buffer[FRAGMENT_SIZE];
350 size_t data_len;
351 xflags_t xflags;
352 tcp_error_t trc;
353 int rc;
354
355 log_msg(LVL_DEBUG, "tcp_sock_recv()");
356
357 socket_id = SOCKET_GET_SOCKET_ID(call);
358 flags = SOCKET_GET_FLAGS(call);
359
360 sock_core = socket_cores_find(&client->sockets, socket_id);
361 if (sock_core == NULL) {
362 async_answer_0(callid, ENOTSOCK);
363 return;
364 }
365
366 socket = (tcp_sockdata_t *)sock_core->specific_data;
367
368 (void)flags;
369
370 trc = tcp_uc_receive(socket->conn, buffer, FRAGMENT_SIZE, &data_len,
371 &xflags);
372
373 switch (trc) {
374 case TCP_EOK:
375 rc = EOK;
376 break;
377 case TCP_ENOTEXIST:
378 case TCP_ECLOSING:
379 rc = ENOTCONN;
380 break;
381 default:
382 assert(false);
383 }
384
385 if (rc != EOK) {
386 async_answer_0(callid, rc);
387 return;
388 }
389
390 if (!async_data_read_receive(&rcallid, &length)) {
391 async_answer_0(callid, EINVAL);
392 return;
393 }
394
395 if (length < data_len) {
396 async_data_read_finalize(rcallid, buffer, length);
397 if (rc == EOK)
398 rc = EOVERFLOW;
399 } else {
400 length = data_len;
401 }
402
403 rc = async_data_read_finalize(rcallid, buffer, length);
404 length = 0;
405
406 SOCKET_SET_READ_DATA_LENGTH(answer, length);
407 answer_call(callid, EOK, &answer, 1);
408
409 /* Push one fragment notification to client's queue */
410 tcp_sock_notify_data(sock_core);
411}
412
413static void tcp_sock_recvfrom(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
414{
415 log_msg(LVL_DEBUG, "tcp_sock_recvfrom()");
416 async_answer_0(callid, ENOTSUP);
417}
418
419static void tcp_sock_close(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
420{
421 int socket_id;
422 socket_core_t *sock_core;
423 tcp_sockdata_t *socket;
424 int rc;
425
426 log_msg(LVL_DEBUG, "tcp_sock_close()");
427 socket_id = SOCKET_GET_SOCKET_ID(call);
428
429 sock_core = socket_cores_find(&client->sockets, socket_id);
430 if (sock_core == NULL) {
431 async_answer_0(callid, ENOTSOCK);
432 return;
433 }
434
435 socket = (tcp_sockdata_t *)sock_core->specific_data;
436 (void) socket;
437 /* XXX Close */
438
439 rc = socket_destroy(net_sess, socket_id, &client->sockets, &gsock,
440 tcp_free_sock_data);
441 if (rc != EOK) {
442 async_answer_0(callid, rc);
443 return;
444 }
445
446 async_answer_0(callid, EOK);
447}
448
449static void tcp_sock_getsockopt(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
450{
451 log_msg(LVL_DEBUG, "tcp_sock_getsockopt()");
452 async_answer_0(callid, ENOTSUP);
453}
454
455static void tcp_sock_setsockopt(tcp_client_t *client, ipc_callid_t callid, ipc_call_t call)
456{
457 log_msg(LVL_DEBUG, "tcp_sock_setsockopt()");
458 async_answer_0(callid, ENOTSUP);
459}
460
461int tcp_sock_connection(async_sess_t *sess, ipc_callid_t iid, ipc_call_t icall)
462{
463 ipc_callid_t callid;
464 ipc_call_t call;
465 tcp_client_t client;
466
467 /* Accept the connection */
468 async_answer_0(iid, EOK);
469
470 client.sess = sess;
471 socket_cores_initialize(&client.sockets);
472
473 while (true) {
474 callid = async_get_call(&call);
475 if (!IPC_GET_IMETHOD(call))
476 break;
477
478 log_msg(LVL_DEBUG, "tcp_sock_connection: METHOD=%d\n",
479 (int)IPC_GET_IMETHOD(call));
480
481 switch (IPC_GET_IMETHOD(call)) {
482 case NET_SOCKET:
483 tcp_sock_socket(&client, callid, call);
484 break;
485 case NET_SOCKET_BIND:
486 tcp_sock_bind(&client, callid, call);
487 break;
488 case NET_SOCKET_LISTEN:
489 tcp_sock_listen(&client, callid, call);
490 break;
491 case NET_SOCKET_CONNECT:
492 tcp_sock_connect(&client, callid, call);
493 break;
494 case NET_SOCKET_ACCEPT:
495 tcp_sock_accept(&client, callid, call);
496 break;
497 case NET_SOCKET_SEND:
498 tcp_sock_send(&client, callid, call);
499 break;
500 case NET_SOCKET_SENDTO:
501 tcp_sock_sendto(&client, callid, call);
502 break;
503 case NET_SOCKET_RECV:
504 tcp_sock_recv(&client, callid, call);
505 break;
506 case NET_SOCKET_RECVFROM:
507 tcp_sock_recvfrom(&client, callid, call);
508 break;
509 case NET_SOCKET_CLOSE:
510 tcp_sock_close(&client, callid, call);
511 break;
512 case NET_SOCKET_GETSOCKOPT:
513 tcp_sock_getsockopt(&client, callid, call);
514 break;
515 case NET_SOCKET_SETSOCKOPT:
516 tcp_sock_setsockopt(&client, callid, call);
517 break;
518 default:
519 async_answer_0(callid, ENOTSUP);
520 break;
521 }
522 }
523
524 return EOK;
525}
526
527/**
528 * @}
529 */
Note: See TracBrowser for help on using the repository browser.