Changeset 779541b in mainline for uspace/lib/c/generic/inet/tcp.c


Ignore:
Timestamp:
2015-05-09T13:43:50Z (9 years ago)
Author:
Jiri Svoboda <jiri@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
1d4b815
Parents:
99ea91b2
Message:

TCP transport layer API - somewhat working.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/lib/c/generic/inet/tcp.c

    r99ea91b2 r779541b  
    3030 * @{
    3131 */
    32 /** @file UDP API
     32/** @file TCP API
    3333 */
    3434
     
    3636#include <inet/endpoint.h>
    3737#include <inet/tcp.h>
     38#include <ipc/services.h>
     39#include <ipc/tcp.h>
     40#include <stdlib.h>
     41
     42#include <stdio.h>
     43
     44static void tcp_cb_conn(ipc_callid_t, ipc_call_t *, void *);
     45
     46static int tcp_callback_create(tcp_t *tcp)
     47{
     48        async_exch_t *exch = async_exchange_begin(tcp->sess);
     49
     50        printf("tcp_callback_create()\n");
     51
     52        aid_t req = async_send_0(exch, TCP_CALLBACK_CREATE, NULL);
     53        int rc = async_connect_to_me(exch, 0, 0, 0, tcp_cb_conn, tcp);
     54        async_exchange_end(exch);
     55
     56        if (rc != EOK)
     57                return rc;
     58
     59        sysarg_t retval;
     60        async_wait_for(req, &retval);
     61
     62        return retval;
     63}
    3864
    3965int tcp_create(tcp_t **rtcp)
    4066{
    41         return 0;
     67        tcp_t *tcp;
     68        service_id_t tcp_svcid;
     69        int rc;
     70
     71        printf("tcp_create()\n");
     72
     73        tcp = calloc(1, sizeof(tcp_t));
     74        if (tcp == NULL) {
     75                rc = ENOMEM;
     76                goto error;
     77        }
     78
     79        list_initialize(&tcp->conn);
     80        list_initialize(&tcp->listener);
     81
     82        rc = loc_service_get_id(SERVICE_NAME_TCP, &tcp_svcid,
     83            IPC_FLAG_BLOCKING);
     84        if (rc != EOK) {
     85                rc = EIO;
     86                goto error;
     87        }
     88
     89        tcp->sess = loc_service_connect(EXCHANGE_SERIALIZE, tcp_svcid,
     90            IPC_FLAG_BLOCKING);
     91        if (tcp->sess == NULL) {
     92                rc = EIO;
     93                goto error;
     94        }
     95
     96        rc = tcp_callback_create(tcp);
     97        if (rc != EOK) {
     98                rc = EIO;
     99                goto error;
     100        }
     101
     102        *rtcp = tcp;
     103        return EOK;
     104error:
     105        free(tcp);
     106        return rc;
    42107}
    43108
    44109void tcp_destroy(tcp_t *tcp)
    45110{
     111        if (tcp == NULL)
     112                return;
     113
     114        async_hangup(tcp->sess);
     115        free(tcp);
    46116}
    47117
     
    49119    tcp_conn_t **rconn)
    50120{
    51         return 0;
     121        async_exch_t *exch;
     122        tcp_conn_t *conn;
     123        ipc_call_t answer;
     124
     125        printf("tcp_conn_create()\n");
     126
     127        conn = calloc(1, sizeof(tcp_conn_t));
     128        if (conn == NULL)
     129                return ENOMEM;
     130
     131        conn->data_avail = false;
     132        fibril_mutex_initialize(&conn->lock);
     133        fibril_condvar_initialize(&conn->cv);
     134
     135        exch = async_exchange_begin(tcp->sess);
     136        aid_t req = async_send_0(exch, TCP_CONN_CREATE, &answer);
     137        sysarg_t rc = async_data_write_start(exch, (void *)epp,
     138            sizeof(inet_ep2_t));
     139        async_exchange_end(exch);
     140
     141        if (rc != EOK) {
     142                sysarg_t rc_orig;
     143                async_wait_for(req, &rc_orig);
     144                if (rc_orig != EOK)
     145                        rc = rc_orig;
     146                goto error;
     147        }
     148
     149        async_wait_for(req, &rc);
     150        if (rc != EOK)
     151                goto error;
     152
     153        conn->tcp = tcp;
     154        conn->id = IPC_GET_ARG1(answer);
     155        conn->cb = cb;
     156        conn->cb_arg = arg;
     157
     158        list_append(&conn->ltcp, &tcp->conn);
     159        *rconn = conn;
     160
     161        return EOK;
     162error:
     163        free(conn);
     164        return (int) rc;
    52165}
    53166
    54167void tcp_conn_destroy(tcp_conn_t *conn)
    55168{
     169        async_exch_t *exch;
     170
     171        printf("tcp_conn_destroy()\n");
     172
     173        if (conn == NULL)
     174                return;
     175
     176        list_remove(&conn->ltcp);
     177
     178        exch = async_exchange_begin(conn->tcp->sess);
     179        sysarg_t rc = async_req_1_0(exch, TCP_CONN_DESTROY, conn->id);
     180        async_exchange_end(exch);
     181
     182        free(conn);
     183        (void) rc;
     184}
     185
     186static int tcp_conn_get(tcp_t *tcp, sysarg_t id, tcp_conn_t **rconn)
     187{
     188        list_foreach(tcp->conn, ltcp, tcp_conn_t, conn) {
     189                if (conn->id == id) {
     190                        *rconn = conn;
     191                        return EOK;
     192                }
     193        }
     194
     195        return EINVAL;
    56196}
    57197
    58198void *tcp_conn_userptr(tcp_conn_t *conn)
    59199{
    60         return NULL;
     200        return conn->cb_arg;
    61201}
    62202
     
    64204    void *larg, tcp_cb_t *cb, void *arg, tcp_listener_t **rlst)
    65205{
     206        async_exch_t *exch;
     207        tcp_listener_t *lst;
     208        ipc_call_t answer;
     209
     210        printf("tcp_listener_create()\n");
     211
     212        lst = calloc(1, sizeof(tcp_listener_t));
     213        if (lst == NULL)
     214                return ENOMEM;
     215
     216        exch = async_exchange_begin(tcp->sess);
     217        aid_t req = async_send_0(exch, TCP_LISTENER_CREATE, &answer);
     218        sysarg_t rc = async_data_write_start(exch, (void *)ep,
     219            sizeof(inet_ep_t));
     220        async_exchange_end(exch);
     221
     222        if (rc != EOK) {
     223                sysarg_t rc_orig;
     224                async_wait_for(req, &rc_orig);
     225                if (rc_orig != EOK)
     226                        rc = rc_orig;
     227                goto error;
     228        }
     229
     230        async_wait_for(req, &rc);
     231        if (rc != EOK)
     232                goto error;
     233
     234        lst->tcp = tcp;
     235        lst->id = IPC_GET_ARG1(answer);
     236        lst->lcb = lcb;
     237        lst->lcb_arg = larg;
     238        lst->cb = cb;
     239        lst->cb_arg = arg;
     240
     241        list_append(&lst->ltcp, &tcp->listener);
     242        *rlst = lst;
     243
     244        return EOK;
     245error:
     246        free(lst);
     247        return (int) rc;
     248}
     249
     250void tcp_listener_destroy(tcp_listener_t *lst)
     251{
     252        async_exch_t *exch;
     253
     254        printf("tcp_listener_destroy()\n");
     255
     256        if (lst == NULL)
     257                return;
     258
     259        list_remove(&lst->ltcp);
     260
     261        exch = async_exchange_begin(lst->tcp->sess);
     262        sysarg_t rc = async_req_1_0(exch, TCP_LISTENER_DESTROY, lst->id);
     263        async_exchange_end(exch);
     264
     265        free(lst);
     266        (void) rc;
     267}
     268
     269void *tcp_listener_userptr(tcp_listener_t *lst)
     270{
     271        return lst->lcb_arg;
     272}
     273
     274int tcp_conn_wait_connected(tcp_conn_t *conn)
     275{
     276        async_usleep(1000 * 1000);
    66277        return 0;
    67278}
    68279
    69 void tcp_listener_destroy(tcp_listener_t *lst)
    70 {
    71 }
    72 
    73 void *tcp_listener_userptr(tcp_listener_t *lst)
    74 {
    75         return NULL;
    76 }
    77 
    78 
    79 int tcp_conn_wait_connected(tcp_conn_t *conn)
    80 {
    81         return 0;
    82 }
    83 
    84280int tcp_conn_send(tcp_conn_t *conn, const void *data, size_t bytes)
    85281{
    86         return 0;
    87 }
     282        async_exch_t *exch;
     283        sysarg_t rc;
     284
     285        printf("tcp_conn_send()\n");
     286
     287        exch = async_exchange_begin(conn->tcp->sess);
     288        aid_t req = async_send_1(exch, TCP_CONN_SEND, conn->id, NULL);
     289
     290        rc = async_data_write_start(exch, data, bytes);
     291        if (rc != EOK) {
     292                async_forget(req);
     293                return rc;
     294        }
     295
     296        async_exchange_end(exch);
     297
     298        if (rc != EOK) {
     299                async_forget(req);
     300                return rc;
     301        }
     302
     303        async_wait_for(req, &rc);
     304        return rc;
     305}
     306
    88307
    89308int tcp_conn_send_fin(tcp_conn_t *conn)
    90309{
    91         return 0;
     310        async_exch_t *exch;
     311
     312        printf("tcp_conn_send_fin()\n");
     313
     314        exch = async_exchange_begin(conn->tcp->sess);
     315        sysarg_t rc = async_req_1_0(exch, TCP_CONN_SEND_FIN, conn->id);
     316        async_exchange_end(exch);
     317
     318        return rc;
    92319}
    93320
    94321int tcp_conn_push(tcp_conn_t *conn)
    95322{
    96         return 0;
    97 }
    98 
    99 void tcp_conn_reset(tcp_conn_t *conn)
    100 {
    101 }
    102 
     323        async_exch_t *exch;
     324
     325        printf("tcp_conn_push()\n");
     326
     327        exch = async_exchange_begin(conn->tcp->sess);
     328        sysarg_t rc = async_req_1_0(exch, TCP_CONN_PUSH, conn->id);
     329        async_exchange_end(exch);
     330
     331        return rc;
     332}
     333
     334int tcp_conn_reset(tcp_conn_t *conn)
     335{
     336        async_exch_t *exch;
     337
     338        printf("tcp_conn_reset()\n");
     339
     340        exch = async_exchange_begin(conn->tcp->sess);
     341        sysarg_t rc = async_req_1_0(exch, TCP_CONN_RESET, conn->id);
     342        async_exchange_end(exch);
     343
     344        return rc;
     345}
    103346
    104347int tcp_conn_recv(tcp_conn_t *conn, void *buf, size_t bsize, size_t *nrecv)
    105348{
    106         return 0;
     349        async_exch_t *exch;
     350        ipc_call_t answer;
     351
     352        printf("tcp_conn_recv() bsize=%zu\n", bsize);
     353
     354        fibril_mutex_lock(&conn->lock);
     355        if (!conn->data_avail) {
     356                printf("returning EAGAIN\n");
     357                fibril_mutex_unlock(&conn->lock);
     358                return EAGAIN;
     359        }
     360
     361        exch = async_exchange_begin(conn->tcp->sess);
     362        aid_t req = async_send_1(exch, TCP_CONN_RECV, conn->id, &answer);
     363        int rc = async_data_read_start(exch, buf, bsize);
     364        async_exchange_end(exch);
     365
     366        if (rc != EOK) {
     367                printf("got rc = %d\n", rc);
     368                async_forget(req);
     369                fibril_mutex_unlock(&conn->lock);
     370                return rc;
     371        }
     372
     373        sysarg_t retval;
     374        async_wait_for(req, &retval);
     375        if (retval != EOK) {
     376                printf("got rc = %d\n", rc);
     377                fibril_mutex_unlock(&conn->lock);
     378                return retval;
     379        }
     380
     381        *nrecv = IPC_GET_ARG1(answer);
     382        fibril_mutex_unlock(&conn->lock);
     383        return EOK;
    107384}
    108385
    109386int tcp_conn_recv_wait(tcp_conn_t *conn, void *buf, size_t bsize, size_t *nrecv)
    110387{
    111         return 0;
     388        async_exch_t *exch;
     389        ipc_call_t answer;
     390
     391        printf("tcp_conn_recv_wait() bsize=%zu\n", bsize);
     392again:
     393        fibril_mutex_lock(&conn->lock);
     394        while (!conn->data_avail) {
     395                printf("wait for data to be avail\n");
     396                fibril_condvar_wait(&conn->cv, &conn->lock);
     397        }
     398
     399        printf("tcp_conn_recv_wait - get data\n");
     400        exch = async_exchange_begin(conn->tcp->sess);
     401        aid_t req = async_send_1(exch, TCP_CONN_RECV_WAIT, conn->id, &answer);
     402        int rc = async_data_read_start(exch, buf, bsize);
     403        printf("tcp_conn_recv_wait - rc = %d\n", rc);
     404        async_exchange_end(exch);
     405
     406        if (rc != EOK) {
     407                printf("got rc=%d\n", rc);
     408                async_forget(req);
     409                if (rc == EAGAIN) {
     410                        conn->data_avail = false;
     411                        fibril_mutex_unlock(&conn->lock);
     412                        goto again;
     413                }
     414                fibril_mutex_unlock(&conn->lock);
     415                return rc;
     416        }
     417
     418        sysarg_t retval;
     419        async_wait_for(req, &retval);
     420        if (retval != EOK) {
     421                printf("got retval != EOK\n");
     422                if (rc == EAGAIN) {
     423                        printf("rc == EAGAIN\n");
     424                        conn->data_avail = false;
     425                }
     426                fibril_mutex_unlock(&conn->lock);
     427                return retval;
     428        }
     429
     430        *nrecv = IPC_GET_ARG1(answer);
     431        fibril_mutex_unlock(&conn->lock);
     432        printf("tcp_conn_recv_wait: nrecv=%zu\n", *nrecv);
     433        printf("received: '");
     434        size_t i;
     435        for (i = 0; i < *nrecv; i++) {
     436                putchar((char)((char *)buf)[i]);
     437        }
     438        printf("'\n");
     439        return EOK;
     440}
     441
     442static void tcp_ev_connected(tcp_t *tcp, ipc_callid_t iid, ipc_call_t *icall)
     443{
     444        printf("tcp_ev_connected()\n");
     445        async_answer_0(iid, ENOTSUP);
     446}
     447
     448static void tcp_ev_conn_failed(tcp_t *tcp, ipc_callid_t iid, ipc_call_t *icall)
     449{
     450        printf("tcp_ev_conn_failed()\n");
     451        async_answer_0(iid, ENOTSUP);
     452}
     453
     454static void tcp_ev_conn_reset(tcp_t *tcp, ipc_callid_t iid, ipc_call_t *icall)
     455{
     456        printf("tcp_ev_conn_reset()\n");
     457        async_answer_0(iid, ENOTSUP);
     458}
     459
     460static void tcp_ev_data(tcp_t *tcp, ipc_callid_t iid, ipc_call_t *icall)
     461{
     462        tcp_conn_t *conn;
     463        sysarg_t conn_id;
     464        int rc;
     465
     466        printf("tcp_ev_data()\n");
     467        conn_id = IPC_GET_ARG1(*icall);
     468
     469        rc = tcp_conn_get(tcp, conn_id, &conn);
     470        if (rc != EOK) {
     471                printf("conn ID %zu not found\n",
     472                    conn_id);
     473                async_answer_0(iid, ENOENT);
     474                return;
     475        }
     476
     477        conn->data_avail = true;
     478        fibril_condvar_broadcast(&conn->cv);
     479
     480        async_answer_0(iid, EOK);
     481}
     482
     483static void tcp_ev_urg_data(tcp_t *tcp, ipc_callid_t iid, ipc_call_t *icall)
     484{
     485        printf("tcp_ev_urg_data()\n");
     486        async_answer_0(iid, ENOTSUP);
     487}
     488
     489static void tcp_cb_conn(ipc_callid_t iid, ipc_call_t *icall, void *arg)
     490{
     491        tcp_t *tcp = (tcp_t *)arg;
     492
     493        async_answer_0(iid, EOK);
     494
     495        printf("tcp_cb_conn()\n");
     496
     497        while (true) {
     498                ipc_call_t call;
     499                ipc_callid_t callid = async_get_call(&call);
     500
     501                printf("tcp_cb_conn() - msg %d\n",
     502                    (int)IPC_GET_IMETHOD(call));
     503                if (!IPC_GET_IMETHOD(call)) {
     504                        /* TODO: Handle hangup */
     505                        return;
     506                }
     507
     508                switch (IPC_GET_IMETHOD(call)) {
     509                case TCP_EV_CONNECTED:
     510                        tcp_ev_connected(tcp, callid, &call);
     511                        break;
     512                case TCP_EV_CONN_FAILED:
     513                        tcp_ev_conn_failed(tcp, callid, &call);
     514                        break;
     515                case TCP_EV_CONN_RESET:
     516                        tcp_ev_conn_reset(tcp, callid, &call);
     517                        break;
     518                case TCP_EV_DATA:
     519                        tcp_ev_data(tcp, callid, &call);
     520                        break;
     521                case TCP_EV_URG_DATA:
     522                        tcp_ev_urg_data(tcp, callid, &call);
     523                        break;
     524                default:
     525                        async_answer_0(callid, ENOTSUP);
     526                        break;
     527                }
     528        }
    112529}
    113530
Note: See TracChangeset for help on using the changeset viewer.