/* * Secure Network Transport Layer Library v2 implementation. * (sntllv2) it superseed all versions before due to the: * - memory consumption * - new features such as pulse emitting * - performance optimization * * This is a proprietary software. See COPYING for further details. * * (c) Askele Group 2013-2015 * */ #include #include #include #include #include #include #include #include #include #ifdef WIN32 #include #define EBADE 1 #define NETDB_SUCCESS 0 #else #include #include #include #include #endif #include #include #include #include #include #include "internal.h" /* locally used functions */ uint8_t _channel_open(conn_t *co, uint16_t *chid) { chnl_t *chan; uint16_t typeid = *chid; /* our type */ uint16_t chidx; usrtc_t *rpc_list = co->rpc_list; usrtc_node_t *node; rpc_typed_list_t *rlist; cx_rpc_list_t *rpclist; node = usrtc_lookup(rpc_list, (void *)&typeid); if(!node) return SNE_EPERM; else rlist = (rpc_typed_list_t *)usrtc_node_getdata(node); if(rlist) rpclist = rlist->rpc_list; else return SNE_FAILED; chan = malloc(sizeof(chnl_t)); if(!chan) return SNE_ENOMEM; /* init channel */ chan->connection = co; chan->rpc_list = rpclist; chan->flags = 0; pthread_mutex_lock(&co->idx_ch_lock); chidx = idx_allocate(&co->idx_ch); pthread_mutex_unlock(&co->idx_ch_lock); if(chidx == IDX_INVAL) { free(chan); return SNE_MCHANNELS; } chan->cid = chidx; co->channels[chidx] = chan; *chid = chidx; return SNE_SUCCESS; } uint8_t _channel_close(conn_t *co, uint16_t chid) { chnl_t *chan; if(chid > 512) return SNE_INVALINDEX; else chan = co->channels[chid]; if(!chan) return SNE_NOSUCHCHAN; pthread_mutex_lock(&co->idx_ch_lock); idx_free(&co->idx_ch, chid); co->channels[chid] = NULL; pthread_mutex_unlock(&co->idx_ch_lock); free(chan); return SNE_SUCCESS; } chnl_t *sxchannel_open(conn_t *co, int type) { chnl_t *chan = NULL; sxmsg_t *msg = NULL; sntllv2_head_t *head; int msgidx, r; if(!co) { r = SNE_FAILED; goto __reterr; } if(!(chan = malloc(sizeof(chnl_t)))) { __enomem: r = SNE_ENOMEM; goto __reterr; } if(!(msg = malloc(sizeof(sxmsg_t)))) goto __enomem; /* early init for the channel */ chan->connection = co; chan->flags = 0; /* early init for the message */ pthread_mutex_init(&msg->wait, NULL); pthread_mutex_lock(&msg->wait); msg->pch = chan; msg->payload = NULL; memset(&msg->mhead, 0, sizeof(sntllv2_head_t)); head = &msg->mhead; /* form a header */ head->attr = SXMSG_PROTO | SXMSG_REPLYREQ | SXMSG_OPEN; head->payload_length = 0; head->reserve = (uint16_t)type; /* try to alloc a message */ pthread_mutex_lock(&co->idx_msg_lock); msgidx = idx_allocate(&co->idx_msg); if(msgidx != IDX_INVAL) co->messages[msgidx] = msg; pthread_mutex_unlock(&co->idx_msg_lock); if(msgidx == IDX_INVAL) { r = SNE_MMESSAGES; goto __reterr2; } /* now we're ready to write it */ r = _sntll_writemsg(co, msg); if(r == SNE_SUCCESS) pthread_mutex_lock(&msg->wait); else goto __reterr3; /* we will wakeup on return */ if(msg->mhead.opcode != SNE_SUCCESS) { r = msg->mhead.opcode; goto __reterr3; } /* ok all is fine */ chan->cid = msg->mhead.reserve; pthread_mutex_lock(&co->idx_ch_lock); idx_reserve(&co->idx_ch, msg->mhead.reserve); co->channels[msg->mhead.reserve] = chan; pthread_mutex_unlock(&co->idx_ch_lock); /* destroy a message */ pthread_mutex_lock(&co->idx_msg_lock); idx_free(&co->idx_msg, msgidx); co->messages[msgidx] = NULL; pthread_mutex_unlock(&co->idx_msg_lock); /* free allocated resources */ pthread_mutex_unlock(&msg->wait); pthread_mutex_destroy(&msg->wait); free(msg); return chan; __reterr3: pthread_mutex_lock(&co->idx_msg_lock); idx_free(&co->idx_msg, msgidx); co->messages[msgidx] = NULL; pthread_mutex_unlock(&co->idx_msg_lock); __reterr2: pthread_mutex_unlock(&msg->wait); pthread_mutex_destroy(&msg->wait); __reterr: if(chan) free(chan); if(msg) free(msg); errno = r; return NULL; } int sxchannel_close(chnl_t *channel) { int r = SNE_SUCCESS; sxmsg_t *msg; sntllv2_head_t *head; conn_t *co; int msgidx; /* check channel validity */ if(!channel) return SNE_FAILED; else if(!(co = channel->connection)) return SNE_FAILED; if(channel->cid > 512) return SNE_IGNORED; if(channel != co->channels[channel->cid]) return SNE_IGNORED; if(!(msg = malloc(sizeof(sxmsg_t)))) return SNE_ENOMEM; head = &msg->mhead; memset(head, 0, sizeof(sntllv2_head_t)); /* setup head */ head->attr = SXMSG_PROTO | SXMSG_REPLYREQ; /* close channel */ head->reserve = channel->cid; /* setup message */ pthread_mutex_init(&msg->wait, NULL); pthread_mutex_lock(&msg->wait); msg->pch = channel; /* allocate it */ pthread_mutex_lock(&co->idx_msg_lock); msgidx = idx_allocate(&co->idx_msg); if(msgidx != IDX_INVAL) co->messages[msgidx] = msg; pthread_mutex_unlock(&co->idx_msg_lock); if(msgidx == IDX_INVAL) { r = SNE_MMESSAGES; goto __reterr2; } r = _sntll_writemsg(co, msg); if(r == SNE_SUCCESS) { pthread_mutex_lock(&msg->wait); r = head->opcode; /* we will free this anyway */ pthread_mutex_lock(&co->idx_ch_lock); idx_free(&co->idx_ch, channel->cid); co->channels[channel->cid] = NULL; pthread_mutex_unlock(&co->idx_ch_lock); free(channel); } pthread_mutex_lock(&co->idx_msg_lock); idx_free(&co->idx_msg, msgidx); co->messages[msgidx] = NULL; pthread_mutex_unlock(&co->idx_msg_lock); __reterr2: pthread_mutex_unlock(&msg->wait); pthread_mutex_destroy(&msg->wait); free(msg); return r; }