Added read and write filters, fixed bugs with pre-queue filters and que-wait callbacks, added ns_tls, ns_cls, and ns_quewait commands.
1 | /* |
2 | * The contents of this file are subject to the AOLserver Public License |
3 | * Version 1.1 (the "License"); you may not use this file except in |
4 | * compliance with the License. You may obtain a copy of the License at |
5 | * http://aolserver.com/. |
6 | * |
7 | * Software distributed under the License is distributed on an "AS IS" |
8 | * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See |
9 | * the License for the specific language governing rights and limitations |
10 | * under the License. |
11 | * |
12 | * The Original Code is AOLserver Code and related documentation |
13 | * distributed by AOL. |
14 | * |
15 | * The Initial Developer of the Original Code is America Online, |
16 | * Inc. Portions created by AOL are Copyright (C) 1999 America Online, |
17 | * Inc. All Rights Reserved. |
18 | * |
19 | * Alternatively, the contents of this file may be used under the terms |
20 | * of the GNU General Public License (the "GPL"), in which case the |
21 | * provisions of GPL are applicable instead of those above. If you wish |
22 | * to allow use of your version of this file only under the terms of the |
23 | * GPL and not to allow others to use your version of this file under the |
24 | * License, indicate your decision by deleting the provisions above and |
25 | * replace them with the notice and other provisions required by the GPL. |
26 | * If you do not delete the provisions above, a recipient may use your |
27 | * version of this file under either the License or the GPL. |
28 | */ |
29 | |
30 | /* |
31 | * tclsock.c -- |
32 | * |
33 | * Tcl commands that let you do TCP sockets. |
34 | */ |
35 | |
36 | static const char *RCSID = "@(#) $Header: /cvsroot-fuse/aolserver/aolserver/nsd/tclsock.c,v 1.25 2009/12/08 04:12:19 jgdavidson Exp $, compiled: " __DATE__ " " __TIME__; |
37 | |
38 | #include "nsd.h" |
39 | |
40 | /* |
41 | * The following structure is used for a socket callback. |
42 | */ |
43 | |
44 | typedef struct TclSockCallback { |
45 | char *server; |
46 | Tcl_Channel chan; |
47 | int when; |
48 | char script[1]; |
49 | } TclSockCallback; |
50 | |
51 | /* |
52 | * The following structure is used for a socket listen callback. |
53 | */ |
54 | |
55 | typedef struct <a href="/cvs/aolserver/aolserver/nsd/listen.c#A_ListenCallback">ListenCallback</a> { |
56 | char *server; |
57 | char script[1]; |
58 | } <a href="/cvs/aolserver/aolserver/nsd/listen.c#A_ListenCallback">ListenCallback</a>; |
59 | |
60 | /* |
61 | * Local functions defined in this file |
62 | */ |
63 | |
64 | static int <a href="/cvs/aolserver/nsopenssl/tclcmds.c#A_GetSet">GetSet</a>(Tcl_Interp *interp, char *flist, int write, fd_set ** ppset, |
65 | fd_set * pset, int *maxPtr); |
66 | static void <a href="/cvs/aolserver/nsopenssl/tclcmds.c#A_AppendReadyFiles">AppendReadyFiles</a>(Tcl_Interp *interp, fd_set * pset, int write, |
67 | char *flist, Tcl_DString *pds); |
68 | static int <a href="/cvs/aolserver/nsopenssl/tclcmds.c#A_EnterSock">EnterSock</a>(Tcl_Interp *interp, SOCKET sock); |
69 | static int <a href="/cvs/aolserver/nsopenssl/tclcmds.c#A_EnterDup">EnterDup</a>(Tcl_Interp *interp, SOCKET sock); |
70 | static int <a href="/cvs/aolserver/nsopenssl/tclcmds.c#A_EnterDupedSocks">EnterDupedSocks</a>(Tcl_Interp *interp, SOCKET sock); |
71 | static int <a href="/cvs/aolserver/aolserver/nsd/tclsock.c#A_SockSetBlockingObj">SockSetBlockingObj</a>(char *value, Tcl_Interp *interp, int objc, |
72 | Tcl_Obj *CONST objv[]); |
73 | static Ns_SockProc <a href="/cvs/aolserver/aolserver/nsd/tclsock.c#A_SockListenCallback">SockListenCallback</a>; |
74 | static Ns_QueueWaitProc <a href="/cvs/aolserver/aolserver/nsd/tclsock.c#A_WaitCallback">WaitCallback</a>; |
75 | |
76 | void |
77 | <a href="/cvs/aolserver/aolserver/nsd/tclsock.c#A_NsTclSockArgProc">NsTclSockArgProc</a>(Tcl_DString *dsPtr, void *arg) |
78 | { |
79 | TclSockCallback *cbPtr = arg; |
80 | |
81 | Tcl_DStringAppendElement(dsPtr, cbPtr->script); |
82 | } |
83 | |
84 | |
85 | /* |
86 | *---------------------------------------------------------------------- |
87 | * |
88 | * <a href="/cvs/aolserver/aolserver/nsd/tclsock.c#A_NsTclQueWaitObjCmd">NsTclQueWaitObjCmd</a> -- |
89 | * |
90 | * Implement the ns_quewait command to register a Tcl script |
91 | * <a href="/cvs/aolserver/aolserver/nsd/driver.c#A_Ns_QueueWait">Ns_QueueWait</a> callback. Unlike the general ns_sockcallback, |
92 | * the script will execute later in the same, connection-bound |
93 | * interp which calls ns_quewait. Thus the interface is |
94 | * closer to Tcl's standard "fileevent" command. |
95 | * |
96 | * Results: |
97 | * Tcl result. |
98 | * |
99 | * Side effects: |
100 | * Depends on callbacks. |
101 | * |
102 | *---------------------------------------------------------------------- |
103 | */ |
104 | |
105 | int |
106 | <a href="/cvs/aolserver/aolserver/nsd/tclsock.c#A_NsTclQueWaitObjCmd">NsTclQueWaitObjCmd</a>(ClientData arg, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) |
107 | { |
108 | TclSockCallback *cbPtr; |
109 | Ns_Conn *conn; |
110 | Tcl_Channel chan; |
111 | SOCKET sock; |
112 | int when; |
113 | Ns_Time timeout; |
114 | static CONST char *opt[] = { |
115 | "readable", "writable", NULL |
116 | }; |
117 | enum { |
118 | ReadIdx, WriteIdx |
119 | } idx; |
120 | |
121 | if (objc != 5) { |
122 | Tcl_WrongNumArgs(interp, 1, objv, "sockId event timeout script"); |
123 | return TCL_ERROR; |
124 | } |
125 | if (<a href="/cvs/aolserver/aolserver/nsd/tclresp.c#A_NsTclGetConn">NsTclGetConn</a>((NsInterp *) arg, &conn) != TCL_OK) { |
126 | return TCL_ERROR; |
127 | } |
128 | chan = Tcl_GetChannel(interp, Tcl_GetString(objv[1]), NULL); |
129 | if (chan == NULL) { |
130 | return TCL_ERROR; |
131 | } |
132 | if (Tcl_GetIndexFromObj(interp, objv[2], opt, "event", 0, |
133 | (int *) &idx) != TCL_OK) { |
134 | return TCL_ERROR; |
135 | } |
136 | switch (idx) { |
137 | case ReadIdx: |
138 | when = NS_SOCK_READ; |
139 | break; |
140 | case WriteIdx: |
141 | when = NS_SOCK_WRITE; |
142 | break; |
143 | } |
144 | if (<a href="/cvs/aolserver/aolserver/nsd/tclfile.c#A_Ns_TclGetOpenFd">Ns_TclGetOpenFd</a>(interp, Tcl_GetString(objv[1]), |
145 | (idx == WriteIdx) ? 1 :0, (int *) &sock) != TCL_OK) { |
146 | return TCL_ERROR; |
147 | } |
148 | if (<a href="/cvs/aolserver/aolserver/nsd/tclobj.c#A_Ns_TclGetTimeFromObj">Ns_TclGetTimeFromObj</a>(interp, objv[3], &timeout) != TCL_OK) { |
149 | return TCL_ERROR; |
150 | } |
151 | if (<a href="/cvs/aolserver/aolserver/nsd/driver.c#A_Ns_QueueWait">Ns_QueueWait</a>(conn, sock, <a href="/cvs/aolserver/aolserver/nsd/tclsock.c#A_WaitCallback">WaitCallback</a>, objv[4], when, &timeout) != NS_OK) { |
152 | Tcl_SetResult(interp, "could not register sock wait", TCL_STATIC); |
153 | return TCL_ERROR; |
154 | } |
155 | Tcl_IncrRefCount(objv[4]); |
156 | return TCL_OK; |
157 | } |
158 | |
159 | |
160 | /* |
161 | *---------------------------------------------------------------------- |
162 | * |
163 | * <a href="/cvs/aolserver/aolserver/nsd/tclsock.c#A_NsTclGetHostObjCmd">NsTclGetHostObjCmd</a>, <a href="/cvs/aolserver/aolserver/nsd/tclsock.c#A_NsTclGetAddrObjCmd">NsTclGetAddrObjCmd</a> -- |
164 | * |
165 | * Performs a forward or reverse DNS lookup. |
166 | * |
167 | * Results: |
168 | * Tcl result. |
169 | * |
170 | * Side effects: |
171 | * Puts a hostname into the tcl result. |
172 | * |
173 | *---------------------------------------------------------------------- |
174 | */ |
175 | |
176 | static int |
177 | <a href="/cvs/aolserver/aolserver/nsd/tclsock.c#A_GetObjCmd">GetObjCmd</a>(Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[], int byaddr) |
178 | { |
179 | Ns_DString ds; |
180 | char *opt, *addr; |
181 | int all = 0; |
182 | int status; |
183 | |
184 | if (byaddr) { |
185 | if (objc < 2 || objc > 3) { |
186 | Tcl_WrongNumArgs(interp, 1, objv, "?-all? address"); |
187 | return TCL_ERROR; |
188 | } |
189 | } else { |
190 | if (objc != 2) { |
191 | Tcl_WrongNumArgs(interp, 1, objv, "address"); |
192 | return TCL_ERROR; |
193 | } |
194 | } |
195 | opt = Tcl_GetString(objv[1]); |
196 | if (objc >= 3 && STREQ(opt, "-all")) { |
197 | all = 1; |
198 | addr = Tcl_GetString(objv[2]); |
199 | } else { |
200 | addr = opt; |
201 | } |
202 | |
203 | <a href="/cvs/aolserver/aolserver/nsd/dstring.c#A_Ns_DStringInit">Ns_DStringInit</a>(&ds); |
204 | if (byaddr) { |
205 | if (all) { |
206 | status = <a href="/cvs/aolserver/aolserver/nsd/dns.c#A_Ns_GetAllAddrByHost">Ns_GetAllAddrByHost</a>(&ds, addr); |
207 | } else { |
208 | status = <a href="/cvs/aolserver/aolserver/nsd/dns.c#A_Ns_GetAddrByHost">Ns_GetAddrByHost</a>(&ds, addr); |
209 | } |
210 | } else { |
211 | status = <a href="/cvs/aolserver/aolserver/nsd/dns.c#A_Ns_GetHostByAddr">Ns_GetHostByAddr</a>(&ds, addr); |
212 | } |
213 | if (status == NS_TRUE) { |
214 | Tcl_SetResult(interp, ds.string, TCL_VOLATILE); |
215 | } |
216 | <a href="/cvs/aolserver/aolserver/nsd/dstring.c#A_Ns_DStringFree">Ns_DStringFree</a>(&ds); |
217 | if (status != NS_TRUE) { |
218 | Tcl_AppendResult(interp, "could not lookup ", addr, NULL); |
219 | return TCL_ERROR; |
220 | } |
221 | return TCL_OK; |
222 | } |
223 | |
224 | int |
225 | <a href="/cvs/aolserver/aolserver/nsd/tclsock.c#A_NsTclGetHostObjCmd">NsTclGetHostObjCmd</a>(ClientData arg, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) |
226 | { |
227 | return <a href="/cvs/aolserver/aolserver/nsd/tclsock.c#A_GetObjCmd">GetObjCmd</a>(interp, objc, objv, 0); |
228 | } |
229 | |
230 | int |
231 | <a href="/cvs/aolserver/aolserver/nsd/tclsock.c#A_NsTclGetAddrObjCmd">NsTclGetAddrObjCmd</a>(ClientData arg, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) |
232 | { |
233 | return <a href="/cvs/aolserver/aolserver/nsd/tclsock.c#A_GetObjCmd">GetObjCmd</a>(interp, objc, objv, 1); |
234 | } |
235 | |
236 | |
237 | /* |
238 | *---------------------------------------------------------------------- |
239 | * |
240 | * <a href="/cvs/aolserver/aolserver/nsd/tclsock.c#A_NsTclSockSetBlockingObjCmd">NsTclSockSetBlockingObjCmd</a> -- |
241 | * |
242 | * Sets a socket blocking. |
243 | * |
244 | * Results: |
245 | * Tcl result. |
246 | * |
247 | * Side effects: |
248 | * None. |
249 | * |
250 | *---------------------------------------------------------------------- |
251 | */ |
252 | |
253 | int |
254 | <a href="/cvs/aolserver/aolserver/nsd/tclsock.c#A_NsTclSockSetBlockingObjCmd">NsTclSockSetBlockingObjCmd</a>(ClientData arg, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) |
255 | { |
256 | return <a href="/cvs/aolserver/aolserver/nsd/tclsock.c#A_SockSetBlockingObj">SockSetBlockingObj</a>("1", interp, objc, objv); |
257 | } |
258 | |
259 | |
260 | /* |
261 | *---------------------------------------------------------------------- |
262 | * |
263 | * <a href="/cvs/aolserver/aolserver/nsd/tclsock.c#A_NsTclSockSetNonBlockingObjCmd">NsTclSockSetNonBlockingObjCmd</a> -- |
264 | * |
265 | * Sets a socket nonblocking. |
266 | * |
267 | * Results: |
268 | * Tcl result. |
269 | * |
270 | * Side effects: |
271 | * None. |
272 | * |
273 | *---------------------------------------------------------------------- |
274 | */ |
275 | |
276 | int |
277 | <a href="/cvs/aolserver/aolserver/nsd/tclsock.c#A_NsTclSockSetNonBlockingObjCmd">NsTclSockSetNonBlockingObjCmd</a>(ClientData arg, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) |
278 | { |
279 | return <a href="/cvs/aolserver/aolserver/nsd/tclsock.c#A_SockSetBlockingObj">SockSetBlockingObj</a>("0", interp, objc, objv); |
280 | } |
281 | |
282 | |
283 | /* |
284 | *---------------------------------------------------------------------- |
285 | * |
286 | * <a href="/cvs/aolserver/aolserver/nsd/tclsock.c#A_NsTclSockNReadObjCmd">NsTclSockNReadObjCmd</a> -- |
287 | * |
288 | * Gets the number of bytes that a socket has waiting to be |
289 | * read. |
290 | * |
291 | * Results: |
292 | * Tcl result. |
293 | * |
294 | * Side effects: |
295 | * None. |
296 | * |
297 | *---------------------------------------------------------------------- |
298 | */ |
299 | |
300 | int |
301 | <a href="/cvs/aolserver/aolserver/nsd/tclsock.c#A_NsTclSockNReadObjCmd">NsTclSockNReadObjCmd</a>(ClientData arg, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) |
302 | { |
303 | int nread; |
304 | Tcl_Channel chan; |
305 | SOCKET sock; |
306 | char buf[20]; |
307 | |
308 | if (objc != 2) { |
309 | Tcl_WrongNumArgs(interp, 1, objv, "sockId"); |
310 | return TCL_ERROR; |
311 | } |
312 | chan = Tcl_GetChannel(interp, Tcl_GetString(objv[1]), NULL); |
313 | if (chan == NULL || <a href="/cvs/aolserver/aolserver/nsd/tclfile.c#A_Ns_TclGetOpenFd">Ns_TclGetOpenFd</a>(interp, Tcl_GetString(objv[1]), 0, |
314 | (int *) &sock) != TCL_OK) { |
315 | return TCL_ERROR; |
316 | } |
317 | if (ns_sockioctl(sock, FIONREAD, &nread) != 0) { |
318 | Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "ns_sockioctl failed: ", |
319 | Tcl_PosixError(interp), NULL); |
320 | return TCL_ERROR; |
321 | } |
322 | nread += Tcl_InputBuffered(chan); |
323 | sprintf(buf, "%d", nread); |
324 | Tcl_SetResult(interp, buf, TCL_VOLATILE); |
325 | return TCL_OK; |
326 | } |
327 | |
328 | |
329 | /* |
330 | *---------------------------------------------------------------------- |
331 | * |
332 | * <a href="/cvs/aolserver/aolserver/nsd/tclsock.c#A_NsTclSockListenObjCmd">NsTclSockListenObjCmd</a> -- |
333 | * |
334 | * Listen on a TCP port. |
335 | * |
336 | * Results: |
337 | * Tcl result. |
338 | * |
339 | * Side effects: |
340 | * Will listen on a port. |
341 | * |
342 | *---------------------------------------------------------------------- |
343 | */ |
344 | |
345 | int |
346 | <a href="/cvs/aolserver/aolserver/nsd/tclsock.c#A_NsTclSockListenObjCmd">NsTclSockListenObjCmd</a>(ClientData arg, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) |
347 | { |
348 | SOCKET sock; |
349 | char *addr; |
350 | int port; |
351 | |
352 | if (objc != 3) { |
353 | Tcl_WrongNumArgs(interp, 1, objv, "address port"); |
354 | return TCL_ERROR; |
355 | } |
356 | addr = Tcl_GetString(objv[1]); |
357 | if (STREQ(addr, "*")) { |
358 | addr = NULL; |
359 | } |
360 | if (Tcl_GetIntFromObj(interp, objv[2], &port) != TCL_OK) { |
361 | return TCL_ERROR; |
362 | } |
363 | sock = <a href="/cvs/aolserver/aolserver/nsd/sock.c#A_Ns_SockListen">Ns_SockListen</a>(addr, port); |
364 | if (sock == INVALID_SOCKET) { |
365 | Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "could not listen on \"", |
366 | Tcl_GetString(objv[1]), ":", |
367 | Tcl_GetString(objv[2]), "\"", NULL); |
368 | return TCL_ERROR; |
369 | } |
370 | return <a href="/cvs/aolserver/nsopenssl/tclcmds.c#A_EnterSock">EnterSock</a>(interp, sock); |
371 | } |
372 | |
373 | |
374 | /* |
375 | *---------------------------------------------------------------------- |
376 | * |
377 | * <a href="/cvs/aolserver/aolserver/nsd/tclsock.c#A_NsTclSockAcceptObjCmd">NsTclSockAcceptObjCmd</a> -- |
378 | * |
379 | * Accept a connection from a listening socket. |
380 | * |
381 | * Results: |
382 | * Tcl result. |
383 | * |
384 | * Side effects: |
385 | * None. |
386 | * |
387 | *---------------------------------------------------------------------- |
388 | */ |
389 | |
390 | int |
391 | <a href="/cvs/aolserver/aolserver/nsd/tclsock.c#A_NsTclSockAcceptObjCmd">NsTclSockAcceptObjCmd</a>(ClientData arg, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) |
392 | { |
393 | SOCKET sock; |
394 | |
395 | if (objc != 2) { |
396 | Tcl_WrongNumArgs(interp, 1, objv, "sockId"); |
397 | return TCL_ERROR; |
398 | } |
399 | if (<a href="/cvs/aolserver/aolserver/nsd/tclfile.c#A_Ns_TclGetOpenFd">Ns_TclGetOpenFd</a>(interp, Tcl_GetString(objv[1]), 0, (int *) &sock) != TCL_OK) { |
400 | return TCL_ERROR; |
401 | } |
402 | sock = <a href="/cvs/aolserver/aolserver/nsd/sock.c#A_Ns_SockAccept">Ns_SockAccept</a>(sock, NULL, 0); |
403 | if (sock == INVALID_SOCKET) { |
404 | Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "accept failed: ", |
405 | Tcl_PosixError(interp), NULL); |
406 | return TCL_ERROR; |
407 | } |
408 | return <a href="/cvs/aolserver/nsopenssl/tclcmds.c#A_EnterDupedSocks">EnterDupedSocks</a>(interp, sock); |
409 | } |
410 | |
411 | |
412 | /* |
413 | *---------------------------------------------------------------------- |
414 | * |
415 | * <a href="/cvs/aolserver/aolserver/nsd/tclsock.c#A_NsTclSockCheckObjCmd">NsTclSockCheckObjCmd</a> -- |
416 | * |
417 | * Check if a socket is still connected, useful for nonblocking. |
418 | * |
419 | * Results: |
420 | * Tcl result. |
421 | * |
422 | * Side effects: |
423 | * None. |
424 | * |
425 | *---------------------------------------------------------------------- |
426 | */ |
427 | |
428 | int |
429 | <a href="/cvs/aolserver/aolserver/nsd/tclsock.c#A_NsTclSockCheckObjCmd">NsTclSockCheckObjCmd</a>(ClientData arg, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) |
430 | { |
431 | Tcl_Obj *objPtr; |
432 | SOCKET sock; |
433 | |
434 | if (objc != 2) { |
435 | Tcl_WrongNumArgs(interp, 1, objv, "sockId"); |
436 | return TCL_ERROR; |
437 | } |
438 | if (<a href="/cvs/aolserver/aolserver/nsd/tclfile.c#A_Ns_TclGetOpenFd">Ns_TclGetOpenFd</a>(interp, Tcl_GetString(objv[1]), 1, (int *) &sock) != TCL_OK) { |
439 | return TCL_ERROR; |
440 | } |
441 | if (send(sock, NULL, 0, 0) != 0) { |
442 | objPtr = Tcl_NewBooleanObj(0); |
443 | } else { |
444 | objPtr = Tcl_NewBooleanObj(1); |
445 | } |
446 | Tcl_SetObjResult(interp, objPtr); |
447 | return TCL_OK; |
448 | } |
449 | |
450 | |
451 | /* |
452 | *---------------------------------------------------------------------- |
453 | * |
454 | * <a href="/cvs/aolserver/aolserver/nsd/tclsock.c#A_NsTclSockOpenObjCmd">NsTclSockOpenObjCmd</a> -- |
455 | * |
456 | * Open a tcp connection to a host/port. |
457 | * |
458 | * Results: |
459 | * Tcl result. |
460 | * |
461 | * Side effects: |
462 | * Will open a connection. |
463 | * |
464 | *---------------------------------------------------------------------- |
465 | */ |
466 | |
467 | int |
468 | <a href="/cvs/aolserver/aolserver/nsd/tclsock.c#A_NsTclSockOpenObjCmd">NsTclSockOpenObjCmd</a>( |
469 | ClientData arg, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] |
470 | ) |
471 | { |
472 | SOCKET sock; |
473 | char *host, *lhost = NULL, *opt, *val; |
474 | int lport = 0, port, first, async = 0, timeout = -1; |
475 | |
476 | if (objc < 3 || objc > 9) { |
477 | syntax: |
478 | Tcl_WrongNumArgs(interp, 1, objv, |
479 | "?(-nonblock | -async) | -timeout seconds? " |
480 | "?-localhost host? ?-localport port? host port"); |
481 | return TCL_ERROR; |
482 | } |
483 | |
484 | /* |
485 | * <a href="/cvs/aolserver/aolserver/nsd/adpparse.c#A_Parse">Parse</a> optional arguments. Note that either the: |
486 | * -nonblock | -async |
487 | * or |
488 | * -timeout seconds |
489 | * combinations are accepted. |
490 | */ |
491 | |
492 | for (first = 1; first < objc; first++) { |
493 | opt= Tcl_GetString(objv[first]); |
494 | if (*opt != '-') { |
495 | break; /* End of options */ |
496 | } |
497 | if (STREQ(opt, "-nonblock") || STREQ(opt, "-async")) { |
498 | if (timeout >= 0) { |
499 | goto syntax; |
500 | } |
501 | async = 1; |
502 | } else if (STREQ(opt, "-localhost")) { |
503 | if (++first >= objc) { |
504 | goto syntax; |
505 | } |
506 | lhost = Tcl_GetString(objv[first]); |
507 | if (*lhost == 0) { |
508 | Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), |
509 | "invalid hostname: must not be empty", NULL); |
510 | return TCL_ERROR; |
511 | } |
512 | } else if (STREQ(opt, "-timeout")) { |
513 | if (++first >= objc || async) { |
514 | goto syntax; |
515 | } |
516 | if (Tcl_GetIntFromObj(interp, objv[first], &timeout) != TCL_OK) { |
517 | return TCL_ERROR; |
518 | } |
519 | } else if (STREQ(opt, "-localport")) { |
520 | if (++first >= objc) { |
521 | goto syntax; |
522 | } |
523 | if (Tcl_GetIntFromObj(interp, objv[first], &lport) != TCL_OK) { |
524 | return TCL_ERROR; |
525 | } |
526 | if (lport < 0) { |
527 | val = Tcl_GetString(objv[first]); |
528 | Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), |
529 | "invalid port: ", val, "; must be > 0", NULL); |
530 | return TCL_ERROR; |
531 | } |
532 | } else { |
533 | Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), |
534 | "invalid option: \"", opt, "\"", NULL); |
535 | return TCL_ERROR; |
536 | } |
537 | } |
538 | |
539 | if ((objc - first) != 2) { |
540 | goto syntax; |
541 | } |
542 | |
543 | /* |
544 | * Get the host to connect to. Bark on invalid entry. |
545 | */ |
546 | |
547 | host = Tcl_GetString(objv[first]); |
548 | if (*host == 0) { |
549 | Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), |
550 | "invalid hostname: must not be empty", NULL); |
551 | return TCL_ERROR; |
552 | } |
553 | |
554 | /* |
555 | * Get the port to connect to. Bark on invalid entry. |
556 | */ |
557 | |
558 | if (Tcl_GetIntFromObj(interp, objv[first+1], &port) != TCL_OK) { |
559 | return TCL_ERROR; |
560 | } else if (port < 0) { |
561 | val = Tcl_GetString(objv[first+1]); |
562 | Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), |
563 | "invalid port: ", val, "; must be > 0", NULL); |
564 | return TCL_ERROR; |
565 | } |
566 | |
567 | /* |
568 | * Perform the connection. |
569 | */ |
570 | |
571 | if (async) { |
572 | sock = <a href="/cvs/aolserver/aolserver/nsd/sock.c#A_Ns_SockAsyncConnect2">Ns_SockAsyncConnect2</a>(host, port, lhost, lport); |
573 | } else if (timeout < 0) { |
574 | sock = <a href="/cvs/aolserver/aolserver/nsd/sock.c#A_Ns_SockConnect2">Ns_SockConnect2</a>(host, port, lhost, lport); |
575 | } else { |
576 | sock = <a href="/cvs/aolserver/aolserver/nsd/sock.c#A_Ns_SockTimedConnect2">Ns_SockTimedConnect2</a>(host, port, lhost, lport, timeout); |
577 | } |
578 | |
579 | if (sock == INVALID_SOCKET) { |
580 | char *why = Tcl_GetErrno() ? Tcl_PosixError(interp) : "reason unknown"; |
581 | Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), |
582 | "can't connect to \"", host, ":", |
583 | Tcl_GetString(objv[first+1]), "\"; ", why, NULL); |
584 | return TCL_ERROR; |
585 | } |
586 | |
587 | return <a href="/cvs/aolserver/nsopenssl/tclcmds.c#A_EnterDupedSocks">EnterDupedSocks</a>(interp, sock); |
588 | } |
589 | |
590 | |
591 | /* |
592 | *---------------------------------------------------------------------- |
593 | * |
594 | * <a href="/cvs/aolserver/aolserver/nsd/tclsock.c#A_NsTclSelectObjCmd">NsTclSelectObjCmd</a> -- |
595 | * |
596 | * Imlements select: basically a tcl version of |
597 | * select(2). |
598 | * |
599 | * Results: |
600 | * Tcl result. |
601 | * |
602 | * Side effects: |
603 | * See docs. |
604 | * |
605 | *---------------------------------------------------------------------- |
606 | */ |
607 | |
608 | int |
609 | <a href="/cvs/aolserver/aolserver/nsd/tclsock.c#A_NsTclSelectObjCmd">NsTclSelectObjCmd</a>(ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) |
610 | { |
611 | fd_set rset, wset, eset, *rPtr, *wPtr, *ePtr; |
612 | int maxfd; |
613 | int i, status, arg; |
614 | Tcl_Channel chan; |
615 | struct timeval tv, *tvPtr; |
616 | Tcl_DString dsRfd, dsNbuf; |
617 | Tcl_Obj **fobjv; |
618 | int fobjc; |
619 | Ns_Time timeout; |
620 | |
621 | status = TCL_ERROR; |
622 | if (objc != 6 && objc != 4) { |
623 | Tcl_WrongNumArgs(interp, 1, objv, "?-timeout sec? rfds wfds efds"); |
624 | return TCL_ERROR; |
625 | } |
626 | if (objc == 4) { |
627 | tvPtr = NULL; |
628 | arg = 1; |
629 | } else { |
630 | tvPtr = &tv; |
631 | if (strcmp(Tcl_GetString(objv[1]), "-timeout") != 0) { |
632 | Tcl_WrongNumArgs(interp, 1, objv, "?-timeout sec? rfds wfds efds"); |
633 | return TCL_ERROR; |
634 | } |
635 | if (<a href="/cvs/aolserver/aolserver/nsd/tclobj.c#A_Ns_TclGetTimeFromObj">Ns_TclGetTimeFromObj</a>(interp, objv[2], &timeout) != TCL_OK) { |
636 | return TCL_ERROR; |
637 | } |
638 | tv.tv_sec = timeout.sec; |
639 | tv.tv_usec = timeout.usec; |
640 | arg = 3; |
641 | } |
642 | |
643 | /* |
644 | * Readable fd's are treated differently because they may |
645 | * have buffered input. Before doing a select, see if they |
646 | * have any waiting data that's been buffered by the channel. |
647 | */ |
648 | |
649 | if (Tcl_ListObjGetElements(interp, objv[arg++], &fobjc, &fobjv) != TCL_OK) { |
650 | return TCL_ERROR; |
651 | } |
652 | Tcl_DStringInit(&dsRfd); |
653 | Tcl_DStringInit(&dsNbuf); |
654 | for (i = 0; i < fobjc; ++i) { |
655 | chan = Tcl_GetChannel(interp, Tcl_GetString(fobjv[i]), NULL); |
656 | if (chan == NULL) { |
657 | goto done; |
658 | } |
659 | if (Tcl_InputBuffered(chan) > 0) { |
660 | Tcl_DStringAppendElement(&dsNbuf, Tcl_GetString(fobjv[i])); |
661 | } else { |
662 | Tcl_DStringAppendElement(&dsRfd, Tcl_GetString(fobjv[i])); |
663 | } |
664 | } |
665 | |
666 | if (dsNbuf.length > 0) { |
667 | /* |
668 | * Since at least one read fd had buffered input, |
669 | * turn the select into a polling select just |
670 | * to pick up anything else ready right now. |
671 | */ |
672 | |
673 | tv.tv_sec = 0; |
674 | tv.tv_usec = 0; |
675 | tvPtr = &tv; |
676 | } |
677 | maxfd = 0; |
678 | if (<a href="/cvs/aolserver/nsopenssl/tclcmds.c#A_GetSet">GetSet</a>(interp, dsRfd.string, 0, &rPtr, &rset, &maxfd) != TCL_OK) { |
679 | goto done; |
680 | } |
681 | if (<a href="/cvs/aolserver/nsopenssl/tclcmds.c#A_GetSet">GetSet</a>(interp, Tcl_GetString(objv[arg++]), 1, &wPtr, &wset, &maxfd) != TCL_OK) { |
682 | goto done; |
683 | } |
684 | if (<a href="/cvs/aolserver/nsopenssl/tclcmds.c#A_GetSet">GetSet</a>(interp, Tcl_GetString(objv[arg++]), 0, &ePtr, &eset, &maxfd) != TCL_OK) { |
685 | goto done; |
686 | } |
687 | |
688 | /* |
689 | * Return immediately if we're not doing a select on anything. |
690 | */ |
691 | |
692 | if (dsNbuf.length == 0 && |
693 | rPtr == NULL && |
694 | wPtr == NULL && |
695 | ePtr == NULL && |
696 | tvPtr == NULL) { |
697 | |
698 | status = TCL_OK; |
699 | } else { |
700 | |
701 | /* |
702 | * Actually perform the select. |
703 | */ |
704 | |
705 | do { |
706 | i = select(maxfd + 1, rPtr, wPtr, ePtr, tvPtr); |
707 | } while (i < 0 && errno == EINTR); |
708 | |
709 | if (i == INVALID_SOCKET) { |
710 | Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "select failed: ", |
711 | Tcl_PosixError(interp), NULL); |
712 | } else { |
713 | if (i == 0) { |
714 | /* |
715 | * The sets can have any random value now |
716 | */ |
717 | |
718 | if (rPtr != NULL) { |
719 | FD_ZERO(rPtr); |
720 | } |
721 | if (wPtr != NULL) { |
722 | FD_ZERO(wPtr); |
723 | } |
724 | if (ePtr != NULL) { |
725 | FD_ZERO(ePtr); |
726 | } |
727 | } |
728 | <a href="/cvs/aolserver/nsopenssl/tclcmds.c#A_AppendReadyFiles">AppendReadyFiles</a>(interp, rPtr, 0, dsRfd.string, &dsNbuf); |
729 | arg -= 2; |
730 | <a href="/cvs/aolserver/nsopenssl/tclcmds.c#A_AppendReadyFiles">AppendReadyFiles</a>(interp, wPtr, 1, Tcl_GetString(objv[arg++]), NULL); |
731 | <a href="/cvs/aolserver/nsopenssl/tclcmds.c#A_AppendReadyFiles">AppendReadyFiles</a>(interp, ePtr, 0, Tcl_GetString(objv[arg++]), NULL); |
732 | status = TCL_OK; |
733 | } |
734 | } |
735 | |
736 | done: |
737 | Tcl_DStringFree(&dsRfd); |
738 | Tcl_DStringFree(&dsNbuf); |
739 | |
740 | return status; |
741 | } |
742 | |
743 | |
744 | /* |
745 | *---------------------------------------------------------------------- |
746 | * |
747 | * <a href="/cvs/aolserver/aolserver/nsd/tclsock.c#A_NsTclSocketPairObjCmd">NsTclSocketPairObjCmd</a> -- |
748 | * |
749 | * Create a new socket pair. |
750 | * |
751 | * Results: |
752 | * Tcl result. |
753 | * |
754 | * Side effects: |
755 | * None. |
756 | * |
757 | *---------------------------------------------------------------------- |
758 | */ |
759 | |
760 | int |
761 | <a href="/cvs/aolserver/aolserver/nsd/tclsock.c#A_NsTclSocketPairObjCmd">NsTclSocketPairObjCmd</a>(ClientData arg, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) |
762 | { |
763 | SOCKET socks[2]; |
764 | |
765 | if (<a href="/cvs/aolserver/aolserver/nsd/fd.c#A_ns_sockpair">ns_sockpair</a>(socks) != 0) { |
766 | Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "<a href="/cvs/aolserver/aolserver/nsd/fd.c#A_ns_sockpair">ns_sockpair</a> failed: ", |
767 | Tcl_PosixError(interp), NULL); |
768 | return TCL_ERROR; |
769 | } |
770 | if (<a href="/cvs/aolserver/nsopenssl/tclcmds.c#A_EnterSock">EnterSock</a>(interp, socks[0]) != TCL_OK) { |
771 | ns_sockclose(socks[1]); |
772 | return TCL_ERROR; |
773 | } |
774 | return <a href="/cvs/aolserver/nsopenssl/tclcmds.c#A_EnterSock">EnterSock</a>(interp, socks[1]); |
775 | } |
776 | |
777 | |
778 | /* |
779 | *---------------------------------------------------------------------- |
780 | * |
781 | * NsTclSockCallbackCmd -- |
782 | * |
783 | * Register a Tcl callback to be run when a certain state exists |
784 | * on a socket. |
785 | * |
786 | * Results: |
787 | * Tcl result. |
788 | * |
789 | * Side effects: |
790 | * A callback will be registered. |
791 | * |
792 | *---------------------------------------------------------------------- |
793 | */ |
794 | |
795 | int |
796 | <a href="/cvs/aolserver/aolserver/nsd/tclsock.c#A_NsTclSockCallbackObjCmd">NsTclSockCallbackObjCmd</a>(ClientData arg, Tcl_Interp *interp, int objc, |
797 | Tcl_Obj *CONST objv[]) |
798 | { |
799 | SOCKET sock; |
800 | int when; |
801 | char *s; |
802 | TclSockCallback *cbPtr; |
803 | NsInterp *itPtr = arg; |
804 | |
805 | if (objc != 4) { |
806 | Tcl_WrongNumArgs(interp, 1, objv, "sockId script when"); |
807 | return TCL_ERROR; |
808 | } |
809 | s = Tcl_GetString(objv[3]); |
810 | when = 0; |
811 | while (*s != '\0') { |
812 | if (*s == 'r') { |
813 | when |= NS_SOCK_READ; |
814 | } else if (*s == 'w') { |
815 | when |= NS_SOCK_WRITE; |
816 | } else if (*s == 'e') { |
817 | when |= NS_SOCK_EXCEPTION; |
818 | } else if (*s == 'x') { |
819 | when |= NS_SOCK_EXIT; |
820 | } else { |
821 | Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "invalid when specification \"", |
822 | Tcl_GetString(objv[3]), |
823 | "\": should be one or more of r, w, e, or x", |
824 | NULL); |
825 | return TCL_ERROR; |
826 | } |
827 | ++s; |
828 | } |
829 | if (when == 0) { |
830 | Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "invalid when specification \"", |
831 | Tcl_GetString(objv[3]), |
832 | "\": should be one or more of r, w, e, or x", |
833 | NULL); |
834 | return TCL_ERROR; |
835 | } |
836 | if (<a href="/cvs/aolserver/aolserver/nsd/tclfile.c#A_Ns_TclGetOpenFd">Ns_TclGetOpenFd</a>(interp, Tcl_GetString(objv[1]), |
837 | (when & NS_SOCK_WRITE), (int *) &sock) != TCL_OK) { |
838 | return TCL_ERROR; |
839 | } |
840 | |
841 | /* |
842 | * Pass a dup of the socket to the callback thread, allowing |
843 | * this thread's cleanup to close the current socket. It's |
844 | * not possible to simply register the channel again with |
845 | * a NULL interp because the Tcl channel code is not entirely |
846 | * thread safe. |
847 | */ |
848 | |
849 | sock = <a href="/cvs/aolserver/aolserver/nsd/nswin32.c#A_ns_sockdup">ns_sockdup</a>(sock); |
850 | cbPtr = ns_malloc(sizeof(TclSockCallback) + Tcl_GetCharLength(objv[2])); |
851 | cbPtr->server = itPtr->servPtr->server; |
852 | cbPtr->chan = NULL; |
853 | cbPtr->when = when; |
854 | strcpy(cbPtr->script, Tcl_GetString(objv[2])); |
855 | if (<a href="/cvs/aolserver/aolserver/nsd/sockcallback.c#A_Ns_SockCallback">Ns_SockCallback</a>(sock, <a href="/cvs/aolserver/aolserver/nsd/tclsock.c#A_NsTclSockProc">NsTclSockProc</a>, cbPtr, |
856 | when | NS_SOCK_EXIT) != NS_OK) { |
857 | Tcl_SetResult(interp, "could not register callback", TCL_STATIC); |
858 | ns_sockclose(sock); |
859 | ns_free(cbPtr); |
860 | return TCL_ERROR; |
861 | } |
862 | return TCL_OK; |
863 | } |
864 | |
865 | |
866 | /* |
867 | *---------------------------------------------------------------------- |
868 | * |
869 | * <a href="/cvs/aolserver/aolserver/nsd/tclsock.c#A_NsTclSockListenCallbackObjCmd">NsTclSockListenCallbackObjCmd</a> -- |
870 | * |
871 | * Listen on a socket and register a callback to run when |
872 | * connections arrive. |
873 | * |
874 | * Results: |
875 | * Tcl result. |
876 | * |
877 | * Side effects: |
878 | * Will register a callback and listen on a socket. |
879 | * |
880 | *---------------------------------------------------------------------- |
881 | */ |
882 | |
883 | int |
884 | <a href="/cvs/aolserver/aolserver/nsd/tclsock.c#A_NsTclSockListenCallbackObjCmd">NsTclSockListenCallbackObjCmd</a>(ClientData arg, Tcl_Interp *interp, int objc, |
885 | Tcl_Obj *CONST objv[]) |
886 | { |
887 | NsInterp *itPtr = arg; |
888 | <a href="/cvs/aolserver/aolserver/nsd/listen.c#A_ListenCallback">ListenCallback</a> *lcbPtr; |
889 | int port; |
890 | char *addr; |
891 | |
892 | if (objc != 4) { |
893 | Tcl_WrongNumArgs(interp, 1, objv, "address port script"); |
894 | return TCL_ERROR; |
895 | } |
896 | if (Tcl_GetIntFromObj(interp, objv[2], &port) != TCL_OK) { |
897 | return TCL_ERROR; |
898 | } |
899 | addr = Tcl_GetString(objv[1]); |
900 | if (STREQ(addr, "*")) { |
901 | addr = NULL; |
902 | } |
903 | lcbPtr = ns_malloc(sizeof(<a href="/cvs/aolserver/aolserver/nsd/listen.c#A_ListenCallback">ListenCallback</a>) + Tcl_GetCharLength(objv[3])); |
904 | lcbPtr->server = itPtr->servPtr->server; |
905 | strcpy(lcbPtr->script, Tcl_GetString(objv[3])); |
906 | if (<a href="/cvs/aolserver/aolserver/nsd/listen.c#A_Ns_SockListenCallback">Ns_SockListenCallback</a>(addr, port, <a href="/cvs/aolserver/aolserver/nsd/tclsock.c#A_SockListenCallback">SockListenCallback</a>, lcbPtr) != NS_OK) { |
907 | Tcl_SetResult(interp, "could not register callback", TCL_STATIC); |
908 | ns_free(lcbPtr); |
909 | return TCL_ERROR; |
910 | } |
911 | return TCL_OK; |
912 | } |
913 | |
914 | |
915 | /* |
916 | *---------------------------------------------------------------------- |
917 | * |
918 | * <a href="/cvs/aolserver/aolserver/nsd/tclsock.c#A_SockSetBlockingObj">SockSetBlockingObj</a> -- |
919 | * |
920 | * Set a socket blocking. |
921 | * |
922 | * Results: |
923 | * Tcl result. |
924 | * |
925 | * Side effects: |
926 | * None. |
927 | * |
928 | *---------------------------------------------------------------------- |
929 | */ |
930 | |
931 | static int |
932 | <a href="/cvs/aolserver/aolserver/nsd/tclsock.c#A_SockSetBlockingObj">SockSetBlockingObj</a>(char *value, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) |
933 | { |
934 | Tcl_Channel chan; |
935 | |
936 | if (objc != 2) { |
937 | Tcl_WrongNumArgs(interp, 1, objv, "sockId"); |
938 | return TCL_ERROR; |
939 | } |
940 | chan = Tcl_GetChannel(interp, Tcl_GetString(objv[1]), NULL); |
941 | if (chan == NULL) { |
942 | return TCL_ERROR; |
943 | } |
944 | return Tcl_SetChannelOption(interp, chan, "-blocking", value); |
945 | } |
946 | |
947 | |
948 | /* |
949 | *---------------------------------------------------------------------- |
950 | * |
951 | * <a href="/cvs/aolserver/nsopenssl/tclcmds.c#A_AppendReadyFiles">AppendReadyFiles</a> -- |
952 | * |
953 | * Find files in an fd_set that are selected and append them to |
954 | * the tcl result, and also an optional passed-in dstring. |
955 | * |
956 | * Results: |
957 | * None. |
958 | * |
959 | * Side effects: |
960 | * Ready files will be appended to pds if not null, and also |
961 | * interp result. |
962 | * |
963 | *---------------------------------------------------------------------- |
964 | */ |
965 | |
966 | static void |
967 | <a href="/cvs/aolserver/nsopenssl/tclcmds.c#A_AppendReadyFiles">AppendReadyFiles</a>(Tcl_Interp *interp, fd_set *setPtr, int write, char *flist, |
968 | Tcl_DString *dsPtr) |
969 | { |
970 | int fargc; |
971 | char **fargv; |
972 | SOCKET sock; |
973 | Tcl_DString ds; |
974 | |
975 | Tcl_DStringInit(&ds); |
976 | if (dsPtr == NULL) { |
977 | dsPtr = &ds; |
978 | } |
979 | Tcl_SplitList(interp, flist, &fargc, (CONST char***)&fargv); |
980 | while (fargc--) { |
981 | <a href="/cvs/aolserver/aolserver/nsd/tclfile.c#A_Ns_TclGetOpenFd">Ns_TclGetOpenFd</a>(interp, fargv[fargc], write, (int *) &sock); |
982 | if (FD_ISSET(sock, setPtr)) { |
983 | Tcl_DStringAppendElement(dsPtr, fargv[fargc]); |
984 | } |
985 | } |
986 | |
987 | /* |
988 | * Append the ready files to the tcl interp. |
989 | */ |
990 | |
991 | Tcl_AppendElement(interp, dsPtr->string); |
992 | ckfree((char *) fargv); |
993 | Tcl_DStringFree(&ds); |
994 | } |
995 | |
996 | |
997 | /* |
998 | *---------------------------------------------------------------------- |
999 | * |
1000 | * <a href="/cvs/aolserver/nsopenssl/tclcmds.c#A_GetSet">GetSet</a> -- |
1001 | * |
1002 | * Take a Tcl list of files and set bits for each in the list in |
1003 | * an fd_set. |
1004 | * |
1005 | * Results: |
1006 | * Tcl result. |
1007 | * |
1008 | * Side effects: |
1009 | * Will set bits in fd_set. ppset may be NULL on error, or |
1010 | * a valid fd_set on success. Max fd will be returned in *maxPtr. |
1011 | * |
1012 | *---------------------------------------------------------------------- |
1013 | */ |
1014 | |
1015 | static int |
1016 | <a href="/cvs/aolserver/nsopenssl/tclcmds.c#A_GetSet">GetSet</a>(Tcl_Interp *interp, char *flist, int write, fd_set **setPtrPtr, |
1017 | fd_set *setPtr, int *maxPtr) |
1018 | { |
1019 | SOCKET sock; |
1020 | int fargc; |
1021 | char **fargv; |
1022 | int status; |
1023 | |
1024 | if (Tcl_SplitList(interp, flist, &fargc, (CONST char***)&fargv) != TCL_OK) { |
1025 | return TCL_ERROR; |
1026 | } |
1027 | if (fargc == 0) { |
1028 | |
1029 | /* |
1030 | * Tcl_SplitList failed, so abort. |
1031 | */ |
1032 | |
1033 | ckfree((char *)fargv); |
1034 | *setPtrPtr = NULL; |
1035 | return TCL_OK; |
1036 | } else { |
1037 | *setPtrPtr = setPtr; |
1038 | } |
1039 | |
1040 | FD_ZERO(setPtr); |
1041 | status = TCL_OK; |
1042 | |
1043 | /* |
1044 | * Loop over each file, try to get its FD, and set the bit in |
1045 | * the fd_set. |
1046 | */ |
1047 | |
1048 | while (fargc--) { |
1049 | if (<a href="/cvs/aolserver/aolserver/nsd/tclfile.c#A_Ns_TclGetOpenFd">Ns_TclGetOpenFd</a>(interp, fargv[fargc], write, |
1050 | (int *) &sock) != TCL_OK) { |
1051 | status = TCL_ERROR; |
1052 | break; |
1053 | } |
1054 | if (sock > (SOCKET) *maxPtr) { |
1055 | *maxPtr = (int) sock; |
1056 | } |
1057 | FD_SET(sock, setPtr); |
1058 | } |
1059 | ckfree((char *) fargv); |
1060 | |
1061 | return status; |
1062 | } |
1063 | |
1064 | |
1065 | /* |
1066 | *---------------------------------------------------------------------- |
1067 | * |
1068 | * <a href="/cvs/aolserver/nsopenssl/tclcmds.c#A_EnterSock">EnterSock</a>, <a href="/cvs/aolserver/nsopenssl/tclcmds.c#A_EnterDup">EnterDup</a>, <a href="/cvs/aolserver/nsopenssl/tclcmds.c#A_EnterDupedSocks">EnterDupedSocks</a> -- |
1069 | * |
1070 | * Append a socket handle to the tcl result and register its |
1071 | * channel. |
1072 | * |
1073 | * Results: |
1074 | * Tcl result. |
1075 | * |
1076 | * Side effects: |
1077 | * Will create channel, append handle to result. |
1078 | * |
1079 | *---------------------------------------------------------------------- |
1080 | */ |
1081 | |
1082 | static int |
1083 | <a href="/cvs/aolserver/nsopenssl/tclcmds.c#A_EnterSock">EnterSock</a>(Tcl_Interp *interp, SOCKET sock) |
1084 | { |
1085 | Tcl_Channel chan; |
1086 | |
1087 | chan = Tcl_MakeTcpClientChannel((ClientData) sock); |
1088 | if (chan == NULL) { |
1089 | Tcl_AppendResult(interp, "could not open socket", NULL); |
1090 | ns_sockclose(sock); |
1091 | return TCL_ERROR; |
1092 | } |
1093 | Tcl_SetChannelOption(interp, chan, "-translation", "binary"); |
1094 | Tcl_RegisterChannel(interp, chan); |
1095 | Tcl_AppendElement(interp, Tcl_GetChannelName(chan)); |
1096 | return TCL_OK; |
1097 | } |
1098 | |
1099 | static int |
1100 | <a href="/cvs/aolserver/nsopenssl/tclcmds.c#A_EnterDup">EnterDup</a>(Tcl_Interp *interp, SOCKET sock) |
1101 | { |
1102 | sock = <a href="/cvs/aolserver/aolserver/nsd/nswin32.c#A_ns_sockdup">ns_sockdup</a>(sock); |
1103 | if (sock == INVALID_SOCKET) { |
1104 | Tcl_AppendResult(interp, "could not dup socket: ", |
1105 | ns_sockstrerror(errno), NULL); |
1106 | return TCL_ERROR; |
1107 | } |
1108 | return <a href="/cvs/aolserver/nsopenssl/tclcmds.c#A_EnterSock">EnterSock</a>(interp, sock); |
1109 | } |
1110 | |
1111 | static int |
1112 | <a href="/cvs/aolserver/nsopenssl/tclcmds.c#A_EnterDupedSocks">EnterDupedSocks</a>(Tcl_Interp *interp, SOCKET sock) |
1113 | { |
1114 | if (<a href="/cvs/aolserver/nsopenssl/tclcmds.c#A_EnterSock">EnterSock</a>(interp, sock) != TCL_OK || |
1115 | <a href="/cvs/aolserver/nsopenssl/tclcmds.c#A_EnterDup">EnterDup</a>(interp, sock) != TCL_OK) { |
1116 | return TCL_ERROR; |
1117 | } |
1118 | return TCL_OK; |
1119 | } |
1120 | |
1121 | |
1122 | /* |
1123 | *---------------------------------------------------------------------- |
1124 | * |
1125 | * <a href="/cvs/aolserver/aolserver/nsd/tclsock.c#A_NsTclSockProc">NsTclSockProc</a> -- |
1126 | * |
1127 | * This is the C wrapper callback that is registered from |
1128 | * callback. |
1129 | * |
1130 | * Results: |
1131 | * NS_TRUE or NS_FALSE on error |
1132 | * |
1133 | * Side effects: |
1134 | * Will run Tcl script. |
1135 | * |
1136 | *---------------------------------------------------------------------- |
1137 | */ |
1138 | |
1139 | int |
1140 | <a href="/cvs/aolserver/aolserver/nsd/tclsock.c#A_NsTclSockProc">NsTclSockProc</a>(SOCKET sock, void *arg, int why) |
1141 | { |
1142 | Tcl_Interp *interp; |
1143 | Tcl_DString script; |
1144 | Tcl_Obj *objPtr; |
1145 | char *w; |
1146 | int result, ok; |
1147 | TclSockCallback *cbPtr = arg; |
1148 | |
1149 | if (why != NS_SOCK_EXIT || (cbPtr->when & NS_SOCK_EXIT)) { |
1150 | Tcl_DStringInit(&script); |
1151 | interp = <a href="/cvs/aolserver/aolserver/nsd/tclinit.c#A_Ns_TclAllocateInterp">Ns_TclAllocateInterp</a>(cbPtr->server); |
1152 | if (cbPtr->chan == NULL) { |
1153 | /* |
1154 | * Create and register the channel on first use. Because |
1155 | * the Tcl channel code is not entirely thread safe, it's |
1156 | * not possible for the scheduling thread to create and |
1157 | * register the channel. |
1158 | */ |
1159 | |
1160 | cbPtr->chan = Tcl_MakeTcpClientChannel((ClientData) sock); |
1161 | if (cbPtr->chan == NULL) { |
1162 | <a href="/cvs/aolserver/aolserver/nsd/log.c#A_Ns_Log">Ns_Log</a>(Error, "could not make channel for sock: %d", sock); |
1163 | why = NS_SOCK_EXIT; |
1164 | goto fail; |
1165 | } |
1166 | Tcl_RegisterChannel(NULL, cbPtr->chan); |
1167 | Tcl_SetChannelOption(NULL, cbPtr->chan, "-translation", "binary"); |
1168 | } |
1169 | Tcl_RegisterChannel(interp, cbPtr->chan); |
1170 | Tcl_DStringAppend(&script, cbPtr->script, -1); |
1171 | Tcl_DStringAppendElement(&script, Tcl_GetChannelName(cbPtr->chan)); |
1172 | if (why == NS_SOCK_READ) { |
1173 | w = "r"; |
1174 | } else if (why == NS_SOCK_WRITE) { |
1175 | w = "w"; |
1176 | } else if (why == NS_SOCK_EXCEPTION) { |
1177 | w = "e"; |
1178 | } else { |
1179 | w = "x"; |
1180 | } |
1181 | Tcl_DStringAppendElement(&script, w); |
1182 | result = Tcl_EvalEx(interp, script.string, script.length, 0); |
1183 | if (result != TCL_OK) { |
1184 | <a href="/cvs/aolserver/aolserver/nsd/tclinit.c#A_Ns_TclLogError">Ns_TclLogError</a>(interp); |
1185 | } else { |
1186 | objPtr = Tcl_GetObjResult(interp); |
1187 | result = Tcl_GetBooleanFromObj(interp, objPtr, &ok); |
1188 | if (result != TCL_OK || !ok) { |
1189 | why = NS_SOCK_EXIT; |
1190 | } |
1191 | } |
1192 | <a href="/cvs/aolserver/aolserver/nsd/tclinit.c#A_Ns_TclDeAllocateInterp">Ns_TclDeAllocateInterp</a>(interp); |
1193 | Tcl_DStringFree(&script); |
1194 | } |
1195 | if (why == NS_SOCK_EXIT) { |
1196 | fail: |
1197 | if (cbPtr->chan != NULL) { |
1198 | Tcl_UnregisterChannel(NULL, cbPtr->chan); |
1199 | } else { |
1200 | ns_sockclose(sock); |
1201 | } |
1202 | ns_free(cbPtr); |
1203 | return NS_FALSE; |
1204 | } |
1205 | return NS_TRUE; |
1206 | } |
1207 | |
1208 | |
1209 | /* |
1210 | *---------------------------------------------------------------------- |
1211 | * |
1212 | * <a href="/cvs/aolserver/aolserver/nsd/tclsock.c#A_WaitCallback">WaitCallback</a> -- |
1213 | * |
1214 | * This is the C wrapper <a href="/cvs/aolserver/aolserver/nsd/driver.c#A_Ns_QueueWait">Ns_QueueWait</a> callback registered in |
1215 | * ns_quewait. |
1216 | * |
1217 | * Results: |
1218 | * None. |
1219 | * |
1220 | * Side effects: |
1221 | * Will run Tcl script. |
1222 | * |
1223 | *---------------------------------------------------------------------- |
1224 | */ |
1225 | |
1226 | static void |
1227 | <a href="/cvs/aolserver/aolserver/nsd/tclsock.c#A_WaitCallback">WaitCallback</a>(Ns_Conn *conn, SOCKET sock, void *arg, int why) |
1228 | { |
1229 | Tcl_Interp *interp = <a href="/cvs/aolserver/aolserver/nsd/tclinit.c#A_Ns_GetConnInterp">Ns_GetConnInterp</a>(conn); |
1230 | Tcl_Obj *objPtr = arg; |
1231 | Tcl_DString ds; |
1232 | char *s; |
1233 | int len; |
1234 | |
1235 | Tcl_DStringInit(&ds); |
1236 | s = Tcl_GetStringFromObj(objPtr, &len); |
1237 | Tcl_DStringAppend(&ds, s, len); |
1238 | |
1239 | /* |
1240 | * NB: While the C interface allows for a single callback |
1241 | * to be registered (NS_SOCK_READ | NS_SOCK_WRITE), the |
1242 | * ns_quewait command enforces only readable or writable |
1243 | * at a time. |
1244 | */ |
1245 | |
1246 | if (why == 0) { |
1247 | s = "timeout"; |
1248 | } else if (why & NS_SOCK_READ) { |
1249 | s = "readable"; |
1250 | } else if (why & NS_SOCK_WRITE) { |
1251 | s = "writable"; |
1252 | } else if (why & NS_SOCK_DROP) { |
1253 | s = "dropped"; |
1254 | } |
1255 | Tcl_DStringAppendElement(&ds, s); |
1256 | if (Tcl_EvalEx(interp, ds.string, ds.length, 0) != TCL_OK) { |
1257 | <a href="/cvs/aolserver/aolserver/nsd/tclinit.c#A_Ns_TclLogError">Ns_TclLogError</a>(interp); |
1258 | } |
1259 | Tcl_DStringFree(&ds); |
1260 | Tcl_DecrRefCount(objPtr); |
1261 | } |
1262 | |
1263 | |
1264 | /* |
1265 | *---------------------------------------------------------------------- |
1266 | * |
1267 | * <a href="/cvs/aolserver/aolserver/nsd/tclsock.c#A_SockListenCallback">SockListenCallback</a> -- |
1268 | * |
1269 | * This is the C wrapper callback that is registered from |
1270 | * listencallback. |
1271 | * |
1272 | * Results: |
1273 | * NS_TRUE or NS_FALSE on error |
1274 | * |
1275 | * Side effects: |
1276 | * Will run Tcl script. |
1277 | * |
1278 | *---------------------------------------------------------------------- |
1279 | */ |
1280 | |
1281 | static int |
1282 | <a href="/cvs/aolserver/aolserver/nsd/tclsock.c#A_SockListenCallback">SockListenCallback</a>(SOCKET sock, void *arg, int why) |
1283 | { |
1284 | <a href="/cvs/aolserver/aolserver/nsd/listen.c#A_ListenCallback">ListenCallback</a> *lcbPtr = arg; |
1285 | Tcl_Interp *interp; |
1286 | Tcl_DString script; |
1287 | Tcl_Obj *listPtr, **objv; |
1288 | int result, objc; |
1289 | |
1290 | interp = <a href="/cvs/aolserver/aolserver/nsd/tclinit.c#A_Ns_TclAllocateInterp">Ns_TclAllocateInterp</a>(lcbPtr->server); |
1291 | result = <a href="/cvs/aolserver/nsopenssl/tclcmds.c#A_EnterDupedSocks">EnterDupedSocks</a>(interp, sock); |
1292 | if (result == TCL_OK) { |
1293 | listPtr = Tcl_GetObjResult(interp); |
1294 | if (Tcl_ListObjGetElements(interp, listPtr, &objc, &objv) == TCL_OK && objc == 2) { |
1295 | Tcl_DStringInit(&script); |
1296 | Tcl_DStringAppend(&script, lcbPtr->script, -1); |
1297 | Tcl_DStringAppendElement(&script, Tcl_GetString(objv[0])); |
1298 | Tcl_DStringAppendElement(&script, Tcl_GetString(objv[1])); |
1299 | result = Tcl_EvalEx(interp, script.string, script.length, 0); |
1300 | Tcl_DStringFree(&script); |
1301 | } |
1302 | } |
1303 | if (result != TCL_OK) { |
1304 | <a href="/cvs/aolserver/aolserver/nsd/tclinit.c#A_Ns_TclLogError">Ns_TclLogError</a>(interp); |
1305 | } |
1306 | <a href="/cvs/aolserver/aolserver/nsd/tclinit.c#A_Ns_TclDeAllocateInterp">Ns_TclDeAllocateInterp</a>(interp); |
1307 | return NS_TRUE; |
1308 | } |
Copyright © 2010 Geeknet, Inc. All rights reserved. Terms of Use