Mercurial > pidgin
annotate src/protocols/icq/socketmanager.c @ 3293:3e37cfdcca73
[gaim-migrate @ 3311]
I think this works
committer: Tailor Script <tailor@pidgin.im>
author | Sean Egan <seanegan@gmail.com> |
---|---|
date | Fri, 31 May 2002 07:35:51 +0000 |
parents | 9965c0bbdb7c |
children |
rev | line source |
---|---|
2086 | 1 /* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
2 | |
3 /* | |
2392
9965c0bbdb7c
[gaim-migrate @ 2405]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
4 * $Id: socketmanager.c 2405 2001-09-29 02:08:00Z warmenhoven $ |
2086 | 5 * |
6 * Copyright (C) 1998-2001, Denis V. Dmitrienko <denis@null.net> and | |
7 * Bill Soudan <soudan@kde.org> | |
8 * | |
9 * This program is free software; you can redistribute it and/or modify | |
10 * it under the terms of the GNU General Public License as published by | |
11 * the Free Software Foundation; either version 2 of the License, or | |
12 * (at your option) any later version. | |
13 * | |
14 * This program is distributed in the hope that it will be useful, | |
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
17 * GNU General Public License for more details. | |
18 * | |
19 * You should have received a copy of the GNU General Public License | |
20 * along with this program; if not, write to the Free Software | |
21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
22 * | |
23 */ | |
24 | |
25 /** | |
26 * The icqlib socket manager is a simple socket abstraction layer, which | |
27 * supports opening and closing sockets as well as installing handler | |
28 * functions for read ready and write ready events. Its purpose is to | |
29 * both unify socket handling in icqlib and expose icqlib's socket | |
30 * requirements so the library client can assist with socket housekeeping. | |
31 * | |
32 * Library clients have two options to support icqlib: | |
33 * | |
34 * 1. Periodically call icq_Main. This will handle all select logic | |
35 * internally. Advantage is implementation ease, disadvantage is wasted | |
36 * CPU cycles because of polling and poor TCP file transfer performance. | |
37 * | |
38 * 2. Install a icq_SocketNotify callback, perform your own socket | |
39 * management, and notify icqlib using the icq_SocketReady method when | |
40 * a socket is ready for reading or writing. Advantage is efficiency, | |
41 * disadvantage is extra code. | |
42 * | |
43 */ | |
44 | |
45 #include <stdlib.h> | |
46 | |
47 #ifdef _WIN32 | |
48 #include <winsock.h> | |
49 #endif | |
50 | |
51 #include "socketmanager.h" | |
52 | |
53 icq_List *icq_SocketList = NULL; | |
54 fd_set icq_FdSets[ICQ_SOCKET_MAX]; | |
55 int icq_MaxSocket; | |
56 | |
57 void (*icq_SocketNotify)(int socket_fd, int type, int status); | |
58 | |
59 /** | |
60 * Creates a new socket using the operating system's socket creation | |
61 * facility. | |
62 */ | |
63 int icq_SocketNew(int domain, int type, int protocol) | |
64 { | |
65 int s = socket(domain, type, protocol); | |
66 | |
67 icq_SocketAlloc(s); | |
68 | |
69 return s; | |
70 } | |
71 | |
72 | |
73 /** | |
74 * Creates a new socket by accepting a connection from a listening | |
75 * socket. | |
76 */ | |
2392
9965c0bbdb7c
[gaim-migrate @ 2405]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2086
diff
changeset
|
77 int icq_SocketAccept(int listens, struct sockaddr *addr, int *addrlen) |
2086 | 78 { |
79 int s = accept(listens, addr, addrlen); | |
80 | |
81 icq_SocketAlloc(s); | |
82 | |
83 return s; | |
84 } | |
85 | |
86 /** | |
87 * Creates a new icq_Socket structure, and appends it to the | |
88 * socketmanager's global socket list. | |
89 */ | |
90 void icq_SocketAlloc(int s) | |
91 { | |
92 if (s != -1) | |
93 { | |
94 icq_Socket *psocket = (icq_Socket *)malloc(sizeof(icq_Socket)); | |
95 int i; | |
96 psocket->socket = s; | |
97 | |
98 for (i=0; i<ICQ_SOCKET_MAX; i++) | |
99 psocket->handlers[i] = NULL; | |
100 | |
101 icq_ListEnqueue(icq_SocketList, psocket); | |
102 } | |
103 } | |
104 | |
105 /** | |
106 * Closes a socket. This function will notify the library client | |
107 * through the icq_SocketNotify callback if the socket had an installed | |
108 * read or write handler. | |
109 */ | |
110 int icq_SocketDelete(int socket_fd) | |
111 { | |
112 #ifdef _WIN32 | |
113 int result = closesocket(socket_fd); | |
114 #else | |
115 int result = close(socket_fd); | |
116 #endif | |
117 | |
118 if (result != -1) | |
119 { | |
120 icq_Socket *s = icq_FindSocket(socket_fd); | |
121 int i; | |
122 | |
123 /* uninstall all handlers - this will take care of notifing library | |
124 * client */ | |
125 for (i=0; i<ICQ_SOCKET_MAX; i++) | |
126 { | |
127 if (s->handlers[i]) | |
128 icq_SocketSetHandler(s->socket, i, NULL, NULL); | |
129 } | |
130 | |
131 icq_ListRemove(icq_SocketList, s); | |
132 free(s); | |
133 } | |
134 | |
135 return result; | |
136 } | |
137 | |
138 /** | |
139 * Installs a socket event handler. The handler will be called when | |
140 * the socket is ready for reading or writing, depending on the type | |
141 * which should be either ICQ_SOCKET_READ or ICQ_SOCKET_WRITE. In | |
142 * addition, user data can be passed to the callback function through | |
143 * the data member. | |
144 */ | |
145 void icq_SocketSetHandler(int socket_fd, int type, icq_SocketHandler handler, | |
146 void *data) | |
147 { | |
148 icq_Socket *s = icq_FindSocket(socket_fd); | |
149 if (s) | |
150 { | |
151 s->data[type] = data; | |
152 s->handlers[type] = handler; | |
153 if (icq_SocketNotify) | |
154 (*icq_SocketNotify)(socket_fd, type, handler ? 1 : 0); | |
155 } | |
156 } | |
157 | |
158 /** | |
159 * Handles a socket ready event by calling the installed callback | |
160 * function, if any. | |
161 */ | |
162 void icq_SocketReady(icq_Socket *s, int type) | |
163 { | |
164 if (s && s->handlers[type]) | |
165 { | |
166 (*s->handlers[type])(s->data[type]); | |
167 } | |
168 } | |
169 | |
170 void icq_HandleReadySocket(int socket_fd, int type) | |
171 { | |
172 icq_SocketReady(icq_FindSocket(socket_fd), type); | |
173 } | |
174 | |
175 int _icq_SocketBuildFdSets(void *p, va_list data) | |
176 { | |
177 icq_Socket *s = p; | |
178 int i; | |
179 (void)data; | |
180 | |
181 for (i=0; i<ICQ_SOCKET_MAX; i++) | |
182 if (s->handlers[i]) { | |
183 FD_SET(s->socket, &(icq_FdSets[i])); | |
184 if (s->socket > icq_MaxSocket) | |
185 icq_MaxSocket = s->socket; | |
186 } | |
187 | |
188 return 0; /* traverse entire icq_List */ | |
189 } | |
190 | |
191 void icq_SocketBuildFdSets() | |
192 { | |
193 int i; | |
194 | |
195 /* clear fdsets */ | |
196 for (i=0; i<ICQ_SOCKET_MAX; i++) | |
197 FD_ZERO(&(icq_FdSets[i])); | |
198 | |
199 icq_MaxSocket = 0; | |
200 | |
201 /* build fd lists for open sockets */ | |
202 (void)icq_ListTraverse(icq_SocketList, _icq_SocketBuildFdSets); | |
203 } | |
204 | |
205 int _icq_SocketHandleReady(void *p, va_list data) | |
206 { | |
207 icq_Socket *s = p; | |
208 int i; | |
209 (void)data; | |
210 | |
211 for (i=0; i<ICQ_SOCKET_MAX; i++) | |
212 if (FD_ISSET(s->socket, &(icq_FdSets[i]))) { | |
213 icq_SocketReady(s, i); | |
214 } | |
215 | |
216 return 0; /* traverse entire icq_List */ | |
217 } | |
218 | |
219 void icq_SocketPoll() | |
220 { | |
221 struct timeval tv; | |
222 | |
223 icq_SocketBuildFdSets(); | |
224 | |
225 tv.tv_sec = 0; tv.tv_usec = 0; | |
226 | |
227 /* determine which sockets require maintenance */ | |
228 select(icq_MaxSocket+1, &(icq_FdSets[ICQ_SOCKET_READ]), | |
229 &(icq_FdSets[ICQ_SOCKET_WRITE]), NULL, &tv); | |
230 | |
231 /* handle ready sockets */ | |
232 (void)icq_ListTraverse(icq_SocketList, _icq_SocketHandleReady); | |
233 } | |
234 | |
235 int _icq_FindSocket(void *p, va_list data) | |
236 { | |
237 int socket_fd = va_arg(data, int); | |
238 return (((icq_Socket *)p)->socket == socket_fd); | |
239 } | |
240 | |
241 icq_Socket *icq_FindSocket(int socket_fd) | |
242 { | |
243 return icq_ListTraverse(icq_SocketList, _icq_FindSocket, socket_fd); | |
244 } | |
245 | |
246 |