⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 event_tcp.c

📁 linux下的pppoe拨号程序源代码; 不错的开源代码
💻 C
字号:
/************************************************************************* event_tcp.c -- implementation of event-driven socket I/O.** Copyright (C) 2001 Roaring Penguin Software Inc.** This program may be distributed according to the terms of the GNU* General Public License, version 2 or (at your option) any later version.** LIC: GPL************************************************************************/static char const RCSID[] ="$Id: event_tcp.c,v 1.6 2002/05/08 13:54:24 dfs Exp $";#include "event_tcp.h"#include <unistd.h>#include <fcntl.h>#include <sys/types.h>#include <stdlib.h>#include <errno.h>#include <string.h>static void free_state(EventTcpState *state);typedef struct EventTcpConnectState_t {    int fd;    EventHandler *conn;    EventTcpConnectFunc f;    void *data;} EventTcpConnectState;/*********************************************************************** %FUNCTION: handle_accept* %ARGUMENTS:*  es -- event selector*  fd -- socket*  flags -- ignored*  data -- the accept callback function* %RETURNS:*  Nothing* %DESCRIPTION:*  Calls accept; if a connection arrives, calls the accept callback*  function with connected descriptor***********************************************************************/static voidhandle_accept(EventSelector *es,	      int fd,	      unsigned int flags,	      void *data){    int conn;    EventTcpAcceptFunc f;    EVENT_DEBUG(("tcp_handle_accept(es=%p, fd=%d, flags=%u, data=%p)\n", es, fd, flags, data));    conn = accept(fd, NULL, NULL);    if (conn < 0) return;    f = (EventTcpAcceptFunc) data;    f(es, conn);}/*********************************************************************** %FUNCTION: handle_connect* %ARGUMENTS:*  es -- event selector*  fd -- socket*  flags -- ignored*  data -- the accept callback function* %RETURNS:*  Nothing* %DESCRIPTION:*  Calls accept; if a connection arrives, calls the accept callback*  function with connected descriptor***********************************************************************/static voidhandle_connect(EventSelector *es,	      int fd,	      unsigned int flags,	      void *data){    int error = 0;    socklen_t len = sizeof(error);    EventTcpConnectState *state = (EventTcpConnectState *) data;    EVENT_DEBUG(("tcp_handle_connect(es=%p, fd=%d, flags=%u, data=%p)\n", es, fd, flags, data));    /* Cancel writable event */    Event_DelHandler(es, state->conn);    state->conn = NULL;    /* Timeout? */    if (flags & EVENT_FLAG_TIMEOUT) {	errno = ETIMEDOUT;	state->f(es, fd, EVENT_TCP_FLAG_TIMEOUT, state->data);	free(state);	return;    }    /* Check for pending error */    if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &len) < 0) {	state->f(es, fd, EVENT_TCP_FLAG_IOERROR, state->data);	free(state);	return;    }    if (error) {	errno = error;	state->f(es, fd, EVENT_TCP_FLAG_IOERROR, state->data);	free(state);	return;    }    /* It looks cool! */    state->f(es, fd, EVENT_TCP_FLAG_COMPLETE, state->data);    free(state);}/*********************************************************************** %FUNCTION: EventTcp_CreateAcceptor* %ARGUMENTS:*  es -- event selector*  socket -- listening socket*  f -- function to call when a connection is accepted*  data -- extra data to pass to f.* %RETURNS:*  An event handler on success, NULL on failure.* %DESCRIPTION:*  Sets up an accepting socket and calls "f" whenever a new*  connection arrives.***********************************************************************/EventHandler *EventTcp_CreateAcceptor(EventSelector *es,			int socket,			EventTcpAcceptFunc f){    int flags;    EVENT_DEBUG(("EventTcp_CreateAcceptor(es=%p, socket=%d)\n", es, socket));    /* Make sure socket is non-blocking */    flags = fcntl(socket, F_GETFL, 0);    if (flags == -1) {	return NULL;    }    if (fcntl(socket, F_SETFL, flags | O_NONBLOCK) == -1) {	return NULL;    }    return Event_AddHandler(es, socket, EVENT_FLAG_READABLE,			    handle_accept, (void *) f);}/*********************************************************************** %FUNCTION: free_state* %ARGUMENTS:*  state -- EventTcpState to free* %RETURNS:*  Nothing* %DESCRIPTION:*  Frees all state associated with the TcpEvent.***********************************************************************/static voidfree_state(EventTcpState *state){    if (!state) return;    EVENT_DEBUG(("tcp_free_state(state=%p)\n", state));    if (state->buf) free(state->buf);    if (state->eh) Event_DelHandler(state->es, state->eh);    free(state);}/*********************************************************************** %FUNCTION: handle_readable* %ARGUMENTS:*  es -- event selector*  fd -- the readable socket*  flags -- ignored*  data -- the EventTcpState object* %RETURNS:*  Nothing* %DESCRIPTION:*  Continues to fill buffer.  Calls callback when done.***********************************************************************/static voidhandle_readable(EventSelector *es,		int fd,		unsigned int flags,		void *data){    EventTcpState *state = (EventTcpState *) data;    int done = state->cur - state->buf;    int togo = state->len - done;    int nread = 0;    int flag;    EVENT_DEBUG(("tcp_handle_readable(es=%p, fd=%d, flags=%u, data=%p)\n", es, fd, flags, data));    /* Timed out? */    if (flags & EVENT_FLAG_TIMEOUT) {	errno = ETIMEDOUT;	(state->f)(es, state->socket, state->buf, done, EVENT_TCP_FLAG_TIMEOUT,		   state->data);	free_state(state);	return;    }    if (state->delim < 0) {	/* Not looking for a delimiter */	/* togo had better not be zero here! */	nread = read(fd, state->cur, togo);	if (nread <= 0) {	    /* Change connection reset to EOF if we have read at least	       one char */	    if (nread < 0 && errno == ECONNRESET && done > 0) {		nread = 0;	    }	    flag = (nread) ? EVENT_TCP_FLAG_IOERROR : EVENT_TCP_FLAG_EOF;	    /* error or EOF */	    (state->f)(es, state->socket, state->buf, done, flag, state->data);	    free_state(state);	    return;	}	state->cur += nread;	done += nread;	if (done >= state->len) {	    /* Read enough! */	    (state->f)(es, state->socket, state->buf, done,		       EVENT_TCP_FLAG_COMPLETE, state->data);	    free_state(state);	    return;	}    } else {	/* Looking for a delimiter */	while ( (togo > 0) && (nread = read(fd, state->cur, 1)) == 1) {	    togo--;	    done++;	    state->cur++;	    if (*(state->cur - 1) == state->delim) break;	}	if (nread <= 0) {	    /* Error or EOF -- check for EAGAIN */	    if (nread < 0 && errno == EAGAIN) return;	}	/* Some other error, or EOF, or delimiter, or read enough */	if (nread < 0) {	    flag = EVENT_TCP_FLAG_IOERROR;	} else if (nread == 0) {	    flag = EVENT_TCP_FLAG_EOF;	} else {	    flag = EVENT_TCP_FLAG_COMPLETE;	}	(state->f)(es, state->socket, state->buf, done, flag, state->data);	free_state(state);	return;    }}/*********************************************************************** %FUNCTION: handle_writeable* %ARGUMENTS:*  es -- event selector*  fd -- the writeable socket*  flags -- ignored*  data -- the EventTcpState object* %RETURNS:*  Nothing* %DESCRIPTION:*  Continues to fill buffer.  Calls callback when done.***********************************************************************/static voidhandle_writeable(EventSelector *es,		int fd,		unsigned int flags,		void *data){    EventTcpState *state = (EventTcpState *) data;    int done = state->cur - state->buf;    int togo = state->len - done;    int n;    /* Timed out? */    if (flags & EVENT_FLAG_TIMEOUT) {	errno = ETIMEDOUT;	(state->f)(es, state->socket, state->buf, done, EVENT_TCP_FLAG_TIMEOUT,		   state->data);	free_state(state);	return;    }    /* togo had better not be zero here! */    n = write(fd, state->cur, togo);    EVENT_DEBUG(("tcp_handle_writeable(es=%p, fd=%d, flags=%u, data=%p)\n", es, fd, flags, data));    if (n <= 0) {	/* error */	if (state->f) {	    (state->f)(es, state->socket, state->buf, done,		       EVENT_TCP_FLAG_IOERROR,		       state->data);	} else {	    close(fd);	}	free_state(state);	return;    }    state->cur += n;    done += n;    if (done >= state->len) {	/* Written enough! */	if (state->f) {	    (state->f)(es, state->socket, state->buf, done,		       EVENT_TCP_FLAG_COMPLETE, state->data);	} else {	    close(fd);	}	free_state(state);	return;    }}/*********************************************************************** %FUNCTION: EventTcp_ReadBuf* %ARGUMENTS:*  es -- event selector*  socket -- socket to read from*  len -- maximum number of bytes to read*  delim -- delimiter at which to stop reading, or -1 if we should*           read exactly len bytes*  f -- function to call on EOF or when all bytes have been read*  timeout -- if non-zero, timeout in seconds after which we cancel*             operation.*  data -- extra data to pass to function f.* %RETURNS:*  A new EventTcpState token or NULL on error* %DESCRIPTION:*  Sets up a handler to fill a buffer from a socket.***********************************************************************/EventTcpState *EventTcp_ReadBuf(EventSelector *es,		 int socket,		 int len,		 int delim,		 EventTcpIOFinishedFunc f,		 int timeout,		 void *data){    EventTcpState *state;    int flags;    struct timeval t;    EVENT_DEBUG(("EventTcp_ReadBuf(es=%p, socket=%d, len=%d, delim=%d, timeout=%d)\n", es, socket, len, delim, timeout));    if (len <= 0) return NULL;    if (socket < 0) return NULL;    /* Make sure socket is non-blocking */    flags = fcntl(socket, F_GETFL, 0);    if (flags == -1) {	return NULL;    }    if (fcntl(socket, F_SETFL, flags | O_NONBLOCK) == -1) {	return NULL;    }    state = malloc(sizeof(EventTcpState));    if (!state) return NULL;    memset(state, 0, sizeof(EventTcpState));    state->socket = socket;    state->buf = malloc(len);    if (!state->buf) {	free_state(state);	return NULL;    }    state->cur = state->buf;    state->len = len;    state->f = f;    state->es = es;    if (timeout <= 0) {	t.tv_sec = -1;	t.tv_usec = -1;    } else {	t.tv_sec = timeout;	t.tv_usec = 0;    }    state->eh = Event_AddHandlerWithTimeout(es, socket, EVENT_FLAG_READABLE,					    t, handle_readable,					    (void *) state);    if (!state->eh) {	free_state(state);	return NULL;    }    state->data = data;    state->delim = delim;    EVENT_DEBUG(("EventTcp_ReadBuf() -> %p\n", state));    return state;}/*********************************************************************** %FUNCTION: EventTcp_WriteBuf* %ARGUMENTS:*  es -- event selector*  socket -- socket to read from*  buf -- buffer to write*  len -- number of bytes to write*  f -- function to call on EOF or when all bytes have been read*  timeout -- timeout after which to cancel operation*  data -- extra data to pass to function f.* %RETURNS:*  A new EventTcpState token or NULL on error* %DESCRIPTION:*  Sets up a handler to fill a buffer from a socket.***********************************************************************/EventTcpState *EventTcp_WriteBuf(EventSelector *es,		  int socket,		  char *buf,		  int len,		  EventTcpIOFinishedFunc f,		  int timeout,		  void *data){    EventTcpState *state;    int flags;    struct timeval t;    EVENT_DEBUG(("EventTcp_WriteBuf(es=%p, socket=%d, len=%d, timeout=%d)\n", es, socket, len, timeout));    if (len <= 0) return NULL;    if (socket < 0) return NULL;    /* Make sure socket is non-blocking */    flags = fcntl(socket, F_GETFL, 0);    if (flags == -1) {	return NULL;    }    if (fcntl(socket, F_SETFL, flags | O_NONBLOCK) == -1) {	return NULL;    }    state = malloc(sizeof(EventTcpState));    if (!state) return NULL;    memset(state, 0, sizeof(EventTcpState));    state->socket = socket;    state->buf = malloc(len);    if (!state->buf) {	free_state(state);	return NULL;    }    memcpy(state->buf, buf, len);    state->cur = state->buf;    state->len = len;    state->f = f;    state->es = es;    if (timeout <= 0) {	t.tv_sec = -1;	t.tv_usec = -1;    } else {	t.tv_sec = timeout;	t.tv_usec = 0;    }    state->eh = Event_AddHandlerWithTimeout(es, socket, EVENT_FLAG_WRITEABLE,					    t, handle_writeable,					    (void *) state);    if (!state->eh) {	free_state(state);	return NULL;    }    state->data = data;    state->delim = -1;    EVENT_DEBUG(("EventTcp_WriteBuf() -> %p\n", state));    return state;}/*********************************************************************** %FUNCTION: EventTcp_Connect* %ARGUMENTS:*  es -- event selector*  fd -- descriptor to connect*  addr -- address to connect to*  addrlen -- length of address*  f -- function to call with connected socket*  data -- extra data to pass to f* %RETURNS:*  Nothing* %DESCRIPTION:*  Does a non-blocking connect on fd***********************************************************************/voidEventTcp_Connect(EventSelector *es,		 int fd,		 struct sockaddr const *addr,		 socklen_t addrlen,		 EventTcpConnectFunc f,		 int timeout,		 void *data){    int flags;    int n;    EventTcpConnectState *state;    struct timeval t;    /* Make sure socket is non-blocking */    flags = fcntl(fd, F_GETFL, 0);    if (flags == -1 || fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) {	f(es, fd, EVENT_TCP_FLAG_IOERROR, data);	return;    }    n = connect(fd, addr, addrlen);    if (n < 0) {	if (errno != EINPROGRESS) {	    f(es, fd, EVENT_TCP_FLAG_IOERROR, data);	    return;	}    }    if (n == 0) { /* Connect succeeded immediately */	f(es, fd, EVENT_TCP_FLAG_COMPLETE, data);	return;    }    state = malloc(sizeof(*state));    if (!state) {	f(es, fd, EVENT_TCP_FLAG_IOERROR, data);	return;    }    state->f = f;    state->fd = fd;    state->data = data;    if (timeout <= 0) {	t.tv_sec = -1;	t.tv_usec = -1;    } else {	t.tv_sec = timeout;	t.tv_usec = 0;    }    state->conn = Event_AddHandlerWithTimeout(es, fd, EVENT_FLAG_WRITEABLE,					      t, handle_connect,					      (void *) state);    if (!state->conn) {	free(state);	f(es, fd, EVENT_TCP_FLAG_IOERROR, data);	return;    }}/*********************************************************************** %FUNCTION: EventTcp_CancelPending* %ARGUMENTS:*  s -- an EventTcpState* %RETURNS:*  Nothing* %DESCRIPTION:*  Cancels the pending event handler***********************************************************************/voidEventTcp_CancelPending(EventTcpState *s){    free_state(s);}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -