/* create a new mysocket, and find space in our mysocket descriptor table */ mysocket_t _mysock_new_mysocket(bool_t is_reliable) { mysock_context_t *connection_context = _mysock_allocate_context(); int k; if (!connection_context) { assert(0); return -1; } /* propagates down to new connections arriving on a listening socket */ connection_context->network_state.is_reliable = is_reliable; /* search for a free mysocket descriptor */ for (k = 0; k < MAX_NUM_CONNECTIONS; ++k) { if (!global_ctx[k]) { global_ctx[k] = connection_context; connection_context->my_sd = k; return k; } } _mysock_free_context(connection_context); errno = EMFILE; return -1; }
/* allocate a new connection context. this keeps track of the working state * between the transport and network layers for a particular connection. the * context is subsequently freed on the network layer's exit. */ static mysock_context_t *_mysock_allocate_context(void) { mysock_context_t *ctx = 0; ctx = (mysock_context_t *) calloc(1, sizeof(mysock_context_t)); assert(ctx); /* by default, sockets are active */ ctx->listen_sd = -1; /* initialise connection condition variable. this is signaled when the * connection is established, i.e. myconnect() or myaccept() should * unblock and return to the calling application. */ PTHREAD_CALL(pthread_cond_init(&ctx->blocking_cond, NULL)); PTHREAD_CALL(pthread_mutex_init(&ctx->blocking_lock, NULL)); /* initialise data ready condition variable. this is signaled when * data is ready from the application or the network. */ PTHREAD_CALL(pthread_cond_init(&ctx->data_ready_cond, NULL)); PTHREAD_CALL(pthread_mutex_init(&ctx->data_ready_lock, NULL)); ctx->blocking = TRUE; /* we unblock once we're connected */ /* initialise underlying network state. this includes creating the actual * socket used for communication to the peer--this is analogous to the * underlying raw IP socket used by a real TCP implementation. */ if (_network_init(ctx, &ctx->network_state) < 0) { _mysock_free_context(ctx); return NULL; } return ctx; }
/* close the given mysocket. note that the semantics of myclose() differ * slightly from a regular close(); STCP doesn't implement WAIT_TIME, so * myclose() simply discards all knowledge of the connection once the * connection is terminated. */ int myclose(mysocket_t sd) { mysock_context_t *ctx = _mysock_get_context(sd); DEBUG_LOG(("***myclose(%d)***\n", sd)); MYSOCK_CHECK(ctx != NULL, EBADF); /* stcp_wait_for_event() needs to wake up on a socket close request */ PTHREAD_CALL(pthread_mutex_lock(&ctx->data_ready_lock)); ctx->close_requested = TRUE; PTHREAD_CALL(pthread_mutex_unlock(&ctx->data_ready_lock)); PTHREAD_CALL(pthread_cond_broadcast(&ctx->data_ready_cond)); /* block until STCP thread exits */ if (ctx->transport_thread_started) { assert(!ctx->listening); assert(ctx->is_active || ctx->listen_sd != -1); PTHREAD_CALL(pthread_join(ctx->transport_thread, NULL)); ctx->transport_thread_started = FALSE; } _network_stop_recv_thread(ctx); if (ctx->listening) { /* remove entry from SYN demultiplexing table */ _mysock_close_passive_socket(ctx); } /* free all resources associated with this mysocket */ _mysock_free_context(ctx); DEBUG_LOG(("myclose(%d) returning...\n", sd)); return 0; }