There are no available options for this view.

Parent Directory Parent Directory | Revision <a href="/cvs/aolserver/aolserver/nsd/log.c#A_Log">Log</a> Revision <a href="/cvs/aolserver/aolserver/nsd/log.c#A_Log">Log</a>

Revision 1.25 - (show annotations) (download) (as text)
Tue Dec 8 04:12:19 2009 UTC (8 years ago) by jgdavidson
Branch: MAIN
CVS Tags: aolserver_v45_r2_rc0, HEAD
Branch point for: aolserver_v45_r2
Changes since 1.24: +132 -2 lines
File MIME type: text/x-chdr
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 }