示例#1
0
文件: net.c 项目: abrady/utils
void net_init(void)
{
	WSADATA wsaData;
    if(0!=WSAStartup(MAKEWORD(2,2), &wsaData))
		abErrorFatal("couldn't startup winsock: %s\n",last_error_str());
    g_netctxt.vers = NET_VERSION;
}
示例#2
0
文件: net.c 项目: abrady/utils
NetServer* netserver_create(NetCtxt *ctxt, U16 port, LinkConnFp conn_callback, LinkDiscoFp disco_callback, MessageFp msg_callback)
{
    struct sockaddr_in service = {0}; // bind
    NetServer *s = NetServer_Create(ctxt);
    s->port = port;
    s->listen_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    s->conn_callback = conn_callback;
    s->disco_callback = disco_callback;
    s->msg_callback = msg_callback;
    
    if(s->listen_sock == INVALID_SOCKET)
    {
        printf("error creating socket %s\n", last_error_str());
        goto error;
    }
    
    if(!sock_set_noblocking(s->listen_sock))
    {
        printf("error setting listen socket to async: %s\n", last_error_str());
        goto error;
    }
    
    service.sin_family = AF_INET;
    service.sin_addr.s_addr = inet_addr("127.0.0.1");
    service.sin_port = htons(port);
    if(bind( s->listen_sock, (SOCKADDR*)&service,sizeof(service)) == SOCKET_ERROR)
    {
        printf("bind failed %s\n",last_error_str());
        goto error;
    }
    
    SOCK_CLEAR_DELAY(s->listen_sock);
    
    if(listen(s->listen_sock,1) == SOCKET_ERROR)
    {
        printf("listen failed %s\n",last_error_str());
        goto error;
    }
    
    return s;
error:
    NetServer_Destroy(&s);
    return NULL;
}
示例#3
0
inline void validate_io(BOOL expression, const char* failMessage)  {
  if(!expression) {
		DWORD lastError = ::GetLastError();
		if(ERROR_IO_PENDING != lastError) {
			std::string errMsg(failMessage);
			errMsg.append(" ");
			errMsg.append(last_error_str(lastError));
			boost::throw_exception(io_exception(errMsg));
		}
	}
}
示例#4
0
文件: net.c 项目: abrady/utils
//----------------------------------------
// helper for raw sockets that are 
// nonblocking, closes the passed socket
// on error
// TODO: optimize for win32 specific, e.g. async accept
//----------------------------------------
SOCKET socket_accept(SOCKET *hlisten_sock, struct sockaddr *client_address)
{
    SOCKET sock;
    int addr_len = sizeof(*client_address);    
    if(!hlisten_sock || *hlisten_sock == INVALID_SOCKET)
        return INVALID_SOCKET;
    sock = accept(*hlisten_sock,
                  client_address,
                  client_address?&addr_len:NULL);
    if(sock < 0)
    {
        if(last_error() != EWOULDBLOCK)
        {
            LOG("accept failed on socket %i: %s\n",*hlisten_sock,last_error_str());
            closesocket(*hlisten_sock);
        }
        return *hlisten_sock = INVALID_SOCKET;
    }
    SOCK_CLEAR_DELAY(sock); 
    return sock;
}
示例#5
0
文件: net.c 项目: abrady/utils
//----------------------------------------
// connect : TCP/UDP layer
// handshake : 
//  - once connected, send handshake
//  - wait for handshake response
//  - process (fail: close)
//----------------------------------------
BOOL netlink_tick(NetLink *c)
{
    MessageFp msg_callback;
    int i;
    char *hdr;
    int n;
    
    if(!c || c->sock == INVALID_SOCKET)
        return FALSE;
    if(!c->connected)
    {
        if(c->s) // server side sends handshake
        {
            LinkHandshake hs = {0};
            
            // remember to add sends below
            assert_infunc_static(sizeof(hs) == 8);
            
            hs.vers = htonl(c->ctxt->vers);
            hs.flags = htonl(0); // todo

            n = 0;
            if(n>=0) n = send(c->sock, (char*)&hs.vers, sizeof(hs.vers), 0);
            if(n>=0) n = send(c->sock, (char*)&hs.flags, sizeof(hs.flags), 0);
            if(n < 0)
            {
                if(last_error() == ENOTCONN) // okay, still connecting
                    return TRUE;
                else
                {
                    LOG("error handshaking client %s",last_error_str());
                    goto netlinktick_error;
                }
            }
            c->connected = TRUE;
        }
        else
        {
            if(sock_canrecv(c->sock,0))
                c->connected = TRUE;
        }
    }
    
    if(!c->handshaken)
    {
        if(!sock_recv(c->sock, &c->recv_frame, &c->closed))
        {
            ERR("error in link %s:%p recv during handshake %s", linkip(c),c,last_error_str());
            goto netlinktick_error;
        }

        if(c->s) // server-side handling of handshake response
        {
            U32 vers_res;
            
            if(achr_size(&c->recv_frame) < sizeof(vers_res))
                return TRUE;
            achr_mv(&vers_res,&c->recv_frame,sizeof(vers_res));
            vers_res = ntohl(vers_res);
            if(vers_res != c->ctxt->vers)
            {
                ERR("%s:%p link handshake responded with wrong version %u should be %u",linkip(c),c,vers_res,c->ctxt->vers);
                goto netlinktick_error;
            }
        }
        else
        {
            U32 tmp;
            LinkHandshake lh = {0};        
            if(achr_size(&c->recv_frame) < sizeof(lh))
                return TRUE;

            assert_infunc_static(sizeof(lh) == 8);
            achr_mv(&lh.vers,&c->recv_frame,sizeof(lh.vers));
            lh.vers = ntohl(lh.vers);
            achr_mv(&lh.flags,&c->recv_frame,sizeof(lh.flags));
            lh.flags = ntohl(lh.flags);

            if(lh.vers != c->ctxt->vers)
            {
                ERR("%s:%p version mismatch between client(%c) and server(%c)",linkip(c),c,c->ctxt->vers,lh.vers);
                goto netlinktick_error;
            }

            tmp = htonl(c->ctxt->vers);
            n = send(c->sock,(char*)&tmp,sizeof(c->ctxt->vers),0);
            if(n < 0)
            {
                ERR("%s:%p couldn't send version response",linkip(c),c);
                goto netlinktick_error;
            }
        }
        c->handshaken = TRUE;
        if(c->conn_callback)
            c->conn_callback(c);
        else if(SAFE_MEMBER(c->s,conn_callback))
            c->s->conn_callback(c);
    }

    // ----------------------------------------
    // recv and turn into packets 

    if(!sock_recv(c->sock, &c->recv_frame, &c->closed))
    {
        ERR("%s:%p recv failed %s",linkip(c),c,last_error_str());
        goto netlinktick_error;
    }
    net_process_frame(c);

    // ----------------------------------------
    // dispatch
    
    n = apak_size(&c->recvs);
    if(n)
    {
        msg_callback = c->msg_callback;
        if(!msg_callback && c->s)
            msg_callback = c->s->msg_callback;
        if(!msg_callback)
        {
            ERR("%s:%p no msg handler for link",linkip(c),c);
            goto netlinktick_error;    
        }
        
        for(i = 0;i < n; ++i)
        {
            Pak *m = c->recvs[i];
            if(!msg_callback(c,m,m->hdr.msgid))
                continue;
            Pak_Destroy(&m);
            apak_rm(&c->recvs,i,1);
        }
    }
    
    n = apak_size(&c->sends);
    if(n)
    {
        hdr = achr_create(sizeof(PakHdr));
        for( i = 0; i < n; ++i ) 
        {
            U32 tmp;
            Pak *p = c->sends[i];
            
            // @todo -AB: encrypted, etc. :09/26/08
            achr_setsize(&hdr,0); 
            tmp = htonl(p->hdr.msgid);
            achr_append(&hdr,(char*)&tmp,sizeof(tmp));
            
            tmp = htonl(p->hdr.id);
            achr_append(&hdr,(char*)&tmp,sizeof(tmp));
            
            tmp = htonl(achr_size(&p->body));
            achr_append(&hdr,(char*)&tmp,sizeof(tmp));        
            
            if(!sock_send(c->sock,&hdr,&p->body))
            {
                if(last_error() == EMSGSIZE) // out of room to send. try again later
                {
                    ERR("%s:%p send buffer full for socket: %s. waiting one tick",linkip(c),c,last_error_str());
                    break;
                }
                ERR("%s:%p failed to send on socket: %s",linkip(c),c,last_error_str());
                net_shutdownlink(c);
                Pak_Destroy(&p);
                break;
            }
            Pak_Destroy(&p);
        }
        achr_destroy(&hdr);
        apak_rm(&c->sends,0,i); // cleanup happens above
    }
    
    // ----------
    // cleanup

    // what are we doing here? The point is to allow a graceful
    // cleanup. At some point one side or the other is supposed
    // to initiate termination by calling 'shutdown'. there are
    // several ways this happens:
    // 1) link recvs 0 bytes : closed. all recvd packets are processed. sends are allowed. when all recv'd paks handled, shutdown is called
    // 2) link calls shutdown: no sends allowed, server should respond with FIN
    // e.g.
    // A: shutdown(send). sends FIN to B
    // B: recv returns 0. sets 'closed' flag. if no msgs to send
    //    will call shutdown itself and close the socket.
    // A: recv returns 0. closesocket

    if(apak_size(&c->sends) == 0 && c->shutdown_req && !c->shutdown)
    {
        shutdown(c->sock,SD_SEND);
        c->shutdown = TRUE;
    }
        
    if(!c->closed)     // @todo -AB: timeout code :09/25/08
        return TRUE;
    else if(apak_size(&c->recvs))
        return TRUE;

    if(!c->shutdown)
    {
        shutdown(c->sock,SD_SEND);
        c->shutdown = TRUE;
    }

    // if this link was made visibile above this layer
    if(c->handshaken)
    {
        if(c->disco_callback)
            c->disco_callback(c);
        else if(SAFE_MEMBER(c->s,disco_callback))
            c->s->disco_callback(c);
    }
    return TRUE;
netlinktick_error:
    closesocket(c->sock);
    c->sock = INVALID_SOCKET;
    return FALSE;
}