Mercurial > pidgin.yaz
diff src/protocols/icq/socketmanager.c @ 2086:424a40f12a6c
[gaim-migrate @ 2096]
moving protocols from plugins/ to src/protocols. making it so that you can select which protocols are compiled statically.
committer: Tailor Script <tailor@pidgin.im>
author | Eric Warmenhoven <eric@warmenhoven.org> |
---|---|
date | Tue, 31 Jul 2001 01:00:39 +0000 |
parents | |
children | 9965c0bbdb7c |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/protocols/icq/socketmanager.c Tue Jul 31 01:00:39 2001 +0000 @@ -0,0 +1,246 @@ +/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ + +/* + * $Id: socketmanager.c 2096 2001-07-31 01:00:39Z warmenhoven $ + * + * Copyright (C) 1998-2001, Denis V. Dmitrienko <denis@null.net> and + * Bill Soudan <soudan@kde.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +/** + * The icqlib socket manager is a simple socket abstraction layer, which + * supports opening and closing sockets as well as installing handler + * functions for read ready and write ready events. Its purpose is to + * both unify socket handling in icqlib and expose icqlib's socket + * requirements so the library client can assist with socket housekeeping. + * + * Library clients have two options to support icqlib: + * + * 1. Periodically call icq_Main. This will handle all select logic + * internally. Advantage is implementation ease, disadvantage is wasted + * CPU cycles because of polling and poor TCP file transfer performance. + * + * 2. Install a icq_SocketNotify callback, perform your own socket + * management, and notify icqlib using the icq_SocketReady method when + * a socket is ready for reading or writing. Advantage is efficiency, + * disadvantage is extra code. + * + */ + +#include <stdlib.h> + +#ifdef _WIN32 +#include <winsock.h> +#endif + +#include "socketmanager.h" + +icq_List *icq_SocketList = NULL; +fd_set icq_FdSets[ICQ_SOCKET_MAX]; +int icq_MaxSocket; + +void (*icq_SocketNotify)(int socket_fd, int type, int status); + +/** + * Creates a new socket using the operating system's socket creation + * facility. + */ +int icq_SocketNew(int domain, int type, int protocol) +{ + int s = socket(domain, type, protocol); + + icq_SocketAlloc(s); + + return s; +} + + +/** + * Creates a new socket by accepting a connection from a listening + * socket. + */ +int icq_SocketAccept(int listens, struct sockaddr *addr, socklen_t *addrlen) +{ + int s = accept(listens, addr, addrlen); + + icq_SocketAlloc(s); + + return s; +} + +/** + * Creates a new icq_Socket structure, and appends it to the + * socketmanager's global socket list. + */ +void icq_SocketAlloc(int s) +{ + if (s != -1) + { + icq_Socket *psocket = (icq_Socket *)malloc(sizeof(icq_Socket)); + int i; + psocket->socket = s; + + for (i=0; i<ICQ_SOCKET_MAX; i++) + psocket->handlers[i] = NULL; + + icq_ListEnqueue(icq_SocketList, psocket); + } +} + +/** + * Closes a socket. This function will notify the library client + * through the icq_SocketNotify callback if the socket had an installed + * read or write handler. + */ +int icq_SocketDelete(int socket_fd) +{ +#ifdef _WIN32 + int result = closesocket(socket_fd); +#else + int result = close(socket_fd); +#endif + + if (result != -1) + { + icq_Socket *s = icq_FindSocket(socket_fd); + int i; + + /* uninstall all handlers - this will take care of notifing library + * client */ + for (i=0; i<ICQ_SOCKET_MAX; i++) + { + if (s->handlers[i]) + icq_SocketSetHandler(s->socket, i, NULL, NULL); + } + + icq_ListRemove(icq_SocketList, s); + free(s); + } + + return result; +} + +/** + * Installs a socket event handler. The handler will be called when + * the socket is ready for reading or writing, depending on the type + * which should be either ICQ_SOCKET_READ or ICQ_SOCKET_WRITE. In + * addition, user data can be passed to the callback function through + * the data member. + */ +void icq_SocketSetHandler(int socket_fd, int type, icq_SocketHandler handler, + void *data) +{ + icq_Socket *s = icq_FindSocket(socket_fd); + if (s) + { + s->data[type] = data; + s->handlers[type] = handler; + if (icq_SocketNotify) + (*icq_SocketNotify)(socket_fd, type, handler ? 1 : 0); + } +} + +/** + * Handles a socket ready event by calling the installed callback + * function, if any. + */ +void icq_SocketReady(icq_Socket *s, int type) +{ + if (s && s->handlers[type]) + { + (*s->handlers[type])(s->data[type]); + } +} + +void icq_HandleReadySocket(int socket_fd, int type) +{ + icq_SocketReady(icq_FindSocket(socket_fd), type); +} + +int _icq_SocketBuildFdSets(void *p, va_list data) +{ + icq_Socket *s = p; + int i; + (void)data; + + for (i=0; i<ICQ_SOCKET_MAX; i++) + if (s->handlers[i]) { + FD_SET(s->socket, &(icq_FdSets[i])); + if (s->socket > icq_MaxSocket) + icq_MaxSocket = s->socket; + } + + return 0; /* traverse entire icq_List */ +} + +void icq_SocketBuildFdSets() +{ + int i; + + /* clear fdsets */ + for (i=0; i<ICQ_SOCKET_MAX; i++) + FD_ZERO(&(icq_FdSets[i])); + + icq_MaxSocket = 0; + + /* build fd lists for open sockets */ + (void)icq_ListTraverse(icq_SocketList, _icq_SocketBuildFdSets); +} + +int _icq_SocketHandleReady(void *p, va_list data) +{ + icq_Socket *s = p; + int i; + (void)data; + + for (i=0; i<ICQ_SOCKET_MAX; i++) + if (FD_ISSET(s->socket, &(icq_FdSets[i]))) { + icq_SocketReady(s, i); + } + + return 0; /* traverse entire icq_List */ +} + +void icq_SocketPoll() +{ + struct timeval tv; + + icq_SocketBuildFdSets(); + + tv.tv_sec = 0; tv.tv_usec = 0; + + /* determine which sockets require maintenance */ + select(icq_MaxSocket+1, &(icq_FdSets[ICQ_SOCKET_READ]), + &(icq_FdSets[ICQ_SOCKET_WRITE]), NULL, &tv); + + /* handle ready sockets */ + (void)icq_ListTraverse(icq_SocketList, _icq_SocketHandleReady); +} + +int _icq_FindSocket(void *p, va_list data) +{ + int socket_fd = va_arg(data, int); + return (((icq_Socket *)p)->socket == socket_fd); +} + +icq_Socket *icq_FindSocket(int socket_fd) +{ + return icq_ListTraverse(icq_SocketList, _icq_FindSocket, socket_fd); +} + +