|
|
1.1 root 1: /* sbbsexec.c */
2:
3: /* Synchronet Windows NT/2000 VDD for FOSSIL and DOS I/O Interrupts */
4:
5: /* $Id: sbbsexec.c,v 1.38 2006/10/28 03:56:36 rswindell Exp $ */
6:
7: /****************************************************************************
8: * @format.tab-size 4 (Plain Text/Source Code File Header) *
9: * @format.use-tabs true (see http://www.synchro.net/ptsc_hdr.html) *
10: * *
11: * Copyright 2006 Rob Swindell - http://www.synchro.net/copyright.html *
12: * *
13: * This program is free software; you can redistribute it and/or *
14: * modify it under the terms of the GNU General Public License *
15: * as published by the Free Software Foundation; either version 2 *
16: * of the License, or (at your option) any later version. *
17: * See the GNU General Public License for more details: gpl.txt or *
18: * http://www.fsf.org/copyleft/gpl.html *
19: * *
20: * Anonymous FTP access to the most recent released source is available at *
21: * ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net *
22: * *
23: * Anonymous CVS access to the development source and modification history *
24: * is available at cvs.synchro.net:/cvsroot/sbbs, example: *
25: * cvs -d :pserver:[email protected]:/cvsroot/sbbs login *
26: * (just hit return, no password is necessary) *
27: * cvs -d :pserver:[email protected]:/cvsroot/sbbs checkout src *
28: * *
29: * For Synchronet coding style and modification guidelines, see *
30: * http://www.synchro.net/source.html *
31: * *
32: * You are encouraged to submit any modifications (preferably in Unix diff *
33: * format) via e-mail to [email protected] *
34: * *
35: * Note: If this box doesn't appear square, then you need to fix your tabs. *
36: ****************************************************************************/
37:
38: #include <windows.h>
39: #include <stdio.h>
40: #include <vddsvc.h>
41: #include "uartdefs.h"
42: #include "vdd_func.h"
43: #include "ringbuf.h"
44: #include "genwrap.h"
45: #include "dirwrap.h"
46: #include "threadwrap.h"
47: #include "ini_file.h"
48:
49: #define INI_FILENAME "sbbsexec.ini"
50: #define RINGBUF_SIZE_IN 10000
51: #define DEFAULT_MAX_MSG_SIZE 4000
52: #define LINEAR_RX_BUFLEN 5000
53:
54: /* UART Parameters and virtual registers */
55: WORD uart_io_base = UART_COM1_IO_BASE; /* COM1 */
56: BYTE uart_irq = UART_COM1_IRQ;
57: BYTE uart_ier_reg = 0;
58: BYTE uart_lcr_reg = UART_LCR_8_DATA_BITS;
59: BYTE uart_mcr_reg = UART_MCR_RTS | UART_MCR_DTR;
60: BYTE uart_lsr_reg = UART_LSR_EMPTY_DATA | UART_LSR_EMPTY_XMIT;
61: BYTE uart_msr_reg = UART_MSR_CTS | UART_MSR_DSR;
62: BYTE uart_scratch_reg = 0;
63: BYTE uart_divisor_latch_lsb = 0x03; /* 38400 */
64: BYTE uart_divisor_latch_msb = 0x00;
65:
66: #if defined (_DEBUG)
67: int log_level = LOG_DEBUG;
68: #else
69: int log_level = LOG_WARNING;
70: #endif
71:
72: BOOL virtualize_uart=TRUE;
73: double yield_interval=1.0;
74: BOOL hangup_supported=TRUE;
75: HANDLE hangup_event=NULL;
76: HANDLE hungup_event=NULL;
77: HANDLE interrupt_event=NULL;
78: HANDLE rdslot=INVALID_HANDLE_VALUE;
79: HANDLE wrslot=INVALID_HANDLE_VALUE;
80: RingBuf rdbuf;
81: str_list_t ini;
82: char ini_fname[MAX_PATH+1];
83: char revision[16];
84:
85: void lputs(int level, char* msg)
86: {
87: char buf[1024];
88: if(level > log_level)
89: return;
90:
91: SAFEPRINTF(buf,"SBBS: %s\r\n", msg);
92: OutputDebugString(buf);
93: }
94:
95: static void lprintf(int level, const char *fmt, ...)
96: {
97: char sbuf[1024];
98: va_list argptr;
99:
100: if(level > log_level)
101: return;
102:
103: va_start(argptr,fmt);
104: _vsnprintf(sbuf,sizeof(sbuf),fmt,argptr);
105: sbuf[sizeof(sbuf)-1]=0;
106: va_end(argptr);
107: lputs(level,sbuf);
108: }
109:
110: void hangup()
111: {
112: if(hangup_supported && hangup_event!=NULL) {
113: lprintf(LOG_DEBUG,"Hanging-up at application request");
114: SetEvent(hangup_event);
115: }
116: }
117:
118: void parse_ini(char* program)
119: {
120: char section[MAX_PATH+1];
121:
122: if(ini==NULL) /* no initialization file */
123: return;
124:
125: /* Read the root section of the sbbsexec.ini file */
126: log_level=iniGetLogLevel(ini,program,"LogLevel",log_level);
127: if(iniGetBool(ini,program,"Debug",FALSE))
128: log_level=LOG_DEBUG;
129: yield_interval=iniGetFloat(ini,program,"YieldInterval",yield_interval);
130: hangup_supported=iniGetBool(ini,program,"CanDisconnect",hangup_supported);
131:
132: lprintf(LOG_INFO,"Parsed %s section of %s"
133: ,program==ROOT_SECTION ? "root" : program
134: ,ini_fname);
135:
136: /* [UART] section */
137: if(program==ROOT_SECTION)
138: SAFECOPY(section,"UART");
139: else
140: SAFEPRINTF(section,"%s.UART",program);
141:
142: virtualize_uart=iniGetBool(ini,section,"Virtualize",virtualize_uart);
143: switch(iniGetInteger(ini,section,"ComPort",0)) {
144: case 1: /* COM1 */
145: uart_irq =UART_COM1_IRQ;
146: uart_io_base =UART_COM1_IO_BASE;
147: break;
148: case 2: /* COM2 */
149: uart_irq =UART_COM2_IRQ;
150: uart_io_base =UART_COM2_IO_BASE;
151: break;
152: case 3: /* COM3 */
153: uart_irq =UART_COM3_IRQ;
154: uart_io_base =UART_COM3_IO_BASE;
155: break;
156: case 4: /* COM4 */
157: uart_irq =UART_COM4_IRQ;
158: uart_io_base =UART_COM4_IO_BASE;
159: break;
160: }
161: uart_irq=(BYTE)iniGetShortInt(ini,section,"IRQ",uart_irq);
162: uart_io_base=iniGetShortInt(ini,section,"Address",uart_io_base);
163:
164: lprintf(LOG_INFO,"Parsed %s section of %s"
165: ,section
166: ,ini_fname);
167: }
168:
169:
170: /* Mutex-protected pending interrupt "queue" */
171: int pending_interrupts = 0;
172: CRITICAL_SECTION interrupt_mutex;
173:
174: void set_interrupt_pending(BYTE intr, BOOL assert)
175: {
176: EnterCriticalSection(&interrupt_mutex);
177: lprintf(LOG_DEBUG,"%sasserting interrupt %02X (pending: %02X, IER: %02X)"
178: ,assert ? "" : "de-", intr
179: ,pending_interrupts
180: ,uart_ier_reg);
181: if(assert) {
182: if(uart_ier_reg&intr) { /* is interrupt enabled? */
183: pending_interrupts |= intr; /* flag as pending */
184: SetEvent(interrupt_event);
185: }
186: } else /* de-assert */
187: pending_interrupts &= ~intr; /* remove as pending */
188:
189: LeaveCriticalSection(&interrupt_mutex);
190: }
191:
192: #define assert_interrupt(i) set_interrupt_pending(i, TRUE)
193: #define deassert_interrupt(i) set_interrupt_pending(i, FALSE)
194:
195: void _cdecl interrupt_thread(void *arg)
196: {
197: while(1) {
198: if(WaitForSingleObject(interrupt_event,INFINITE)!=WAIT_OBJECT_0)
199: break;
200: if((uart_ier_reg&pending_interrupts) != 0) {
201: lprintf(LOG_DEBUG,"VDDSimulateInterrupt (pending: %02X) - IER: %02X"
202: ,pending_interrupts, uart_ier_reg);
203: VDDSimulateInterrupt(ICA_MASTER, uart_irq, /* count: */1);
204: }
205: #if 0
206: /* "Real 16550s should always reassert
207: * this interrupt whenever the transmitter is idle and
208: * the interrupt is enabled."
209: */
210: if(pending_interrupts==0 && uart_ier_reg&UART_IER_TX_EMPTY)
211: pending_interrupts|=UART_IER_TX_EMPTY;
212: #endif
213: }
214: }
215:
216: void _cdecl input_thread(void* arg)
217: {
218: char buf[LINEAR_RX_BUFLEN];
219: int count;
220:
221: while(1) {
222: count=0;
223: if(!ReadFile(rdslot,buf,sizeof(buf),&count,NULL)) {
224: if(GetLastError()==ERROR_HANDLE_EOF) /* closed by VDD_CLOSE */
225: break;
226: lprintf(LOG_ERR,"!input_thread: ReadFile Error %d (size=%d)"
227: ,GetLastError(),count);
228: continue;
229: }
230: if(count==0) {
231: lprintf(LOG_ERR,"!input_thread: ReadFile read 0");
232: continue;
233: }
234: RingBufWrite(&rdbuf,buf,count);
235: /* Set the "Data ready" bit in the LSR */
236: uart_lsr_reg |= UART_LSR_DATA_READY;
237:
238: assert_interrupt(UART_IER_RX_DATA); /* assert rx data interrupt */
239: }
240: }
241:
242: unsigned vdd_read(BYTE* p, unsigned count)
243: {
244: sem_wait(rdbuf.sem);
245: count=RingBufRead(&rdbuf,p,count);
246: if(count==0)
247: lprintf(LOG_ERR,"!VDD_READ: RingBufRead read 0");
248:
249: return(count);
250: }
251:
252: unsigned yields=0;
253:
254: void yield()
255: {
256: yields++;
257: lprintf(LOG_DEBUG,"Yielding (yields=%u)", yields);
258: Sleep(1);
259: }
260:
261: long double last_yield=0;
262:
263: void maybe_yield()
264: {
265: long double t;
266:
267: t=xp_timer();
268:
269: if(yield_interval && (t-last_yield)*1000.0 >= yield_interval) {
270: yield();
271: last_yield=t;
272: }
273: }
274:
275: void reset_yield()
276: {
277: last_yield=xp_timer();
278: }
279:
280: /***********************/
281: /* UART Virtualization */
282: /***********************/
283:
284: static char *chr(uchar ch)
285: {
286: static char str[25];
287:
288: if(ch>=' ' && ch<='~')
289: sprintf(str,"'%c' (%02Xh)",ch,ch);
290: else if(ch<' ')
291: sprintf(str,"^%c (%02Xh)",'@'+ch,ch);
292: else
293: sprintf(str,"%u (%02Xh)",ch,ch);
294: return(str);
295: }
296:
297: VOID uart_wrport(WORD port, BYTE data)
298: {
299: int reg = port - uart_io_base;
300: int retval;
301:
302: lprintf(LOG_DEBUG,"write of port: %x (%s) <- %02X", port, uart_reg_desc[reg], data);
303:
304: switch(reg) {
305: case UART_BASE:
306: if(uart_lcr_reg&UART_LCR_DLAB) {
307: uart_divisor_latch_lsb = data;
308: lprintf(LOG_DEBUG,"set divisor latch low byte: %02X", data);
309: } else {
310: lprintf(LOG_DEBUG,"WRITE DATA: %s", chr(data));
311: if(!WriteFile(wrslot,&data,sizeof(BYTE),&retval,NULL)) {
312: lprintf(LOG_ERR,"!VDD_WRITE: WriteFile Error %d (size=%d)"
313: ,GetLastError(),retval);
314: } else {
315: assert_interrupt(UART_IER_TX_EMPTY);
316: reset_yield();
317: }
318: }
319: break;
320: case UART_IER:
321: if(uart_lcr_reg&UART_LCR_DLAB) {
322: uart_divisor_latch_msb = data;
323: lprintf(LOG_DEBUG,"set divisor latch high byte: %02X", data);
324: } else
325: uart_ier_reg = data;
326: assert_interrupt(UART_IER_TX_EMPTY); /* should this be re-asserted for all writes? */
327: break;
328: case UART_IIR: /* FCR not supported */
329: break;
330: case UART_LCR:
331: uart_lcr_reg = data;
332: break;
333: case UART_MCR:
334: uart_mcr_reg = data;
335: if((uart_mcr_reg&UART_MCR_DTR) == 0) /* Dropping DTR (i.e. "hangup") */
336: hangup();
337: break;
338: case UART_SCRATCH:
339: uart_scratch_reg = data;
340: break;
341: default:
342: lprintf(LOG_ERR,"UNSUPPORTED register: %u", reg);
343: break;
344:
345: }
346: }
347:
348: VOID uart_rdport(WORD port, PBYTE data)
349: {
350: int reg = port - uart_io_base;
351: DWORD avail;
352:
353: lprintf(LOG_DEBUG,"read of port: %x (%s)", port, uart_reg_desc[reg]);
354:
355: switch(reg) {
356: case UART_BASE:
357: if(uart_lcr_reg&UART_LCR_DLAB) {
358: lprintf(LOG_DEBUG,"reading divisor latch LSB");
359: *data = uart_divisor_latch_lsb;
360: break;
361: }
362: if((avail=RingBufFull(&rdbuf))!=0) {
363: vdd_read(data,sizeof(BYTE));
364: lprintf(LOG_DEBUG,"READ DATA: %s", chr(*data));
365: avail--;
366: reset_yield();
367: } else
368: *data=0;
369: if(avail==0) {
370: lprintf(LOG_DEBUG,"No more data");
371: /* Clear the data ready bit in the LSR */
372: uart_lsr_reg &= ~UART_LSR_DATA_READY;
373:
374: /* Clear data ready interrupt identification in IIR */
375: deassert_interrupt(UART_IER_RX_DATA);
376: } else /* re-assert RX data (increment the semaphore) */
377: assert_interrupt(UART_IER_RX_DATA);
378: break;
379: case UART_IER:
380: if(uart_lcr_reg&UART_LCR_DLAB) {
381: lprintf(LOG_DEBUG,"reading divisor latch MSB");
382: *data = uart_divisor_latch_msb;
383: } else
384: *data = uart_ier_reg;
385: break;
386: case UART_IIR:
387: /* Report IIR based on *priority* of pending interrupts */
388: if(pending_interrupts & UART_IER_LINE_STATUS)
389: *data = UART_IIR_LINE_STATUS;
390: else if(pending_interrupts & UART_IER_RX_DATA)
391: *data = UART_IIR_RX_DATA;
392: else if(pending_interrupts & UART_IER_TX_EMPTY) {
393: *data = UART_IIR_TX_EMPTY;
394: /* "Transmit Holding Register Empty" interrupt */
395: /* is reset on read of IIR */
396: deassert_interrupt(UART_IER_TX_EMPTY);
397: }
398: else if(pending_interrupts & UART_IER_MODEM_STATUS)
399: *data = UART_IIR_MODEM_STATUS;
400: else
401: *data = UART_IIR_NONE;
402: break;
403: case UART_LCR:
404: *data = uart_lcr_reg;
405: break;
406: case UART_MCR:
407: *data = uart_mcr_reg;
408: break;
409: case UART_LSR:
410: *data = uart_lsr_reg;
411: maybe_yield();
412: /* Clear line status interrupt pending */
413: deassert_interrupt(UART_IER_LINE_STATUS);
414: break;
415: case UART_MSR:
416: if(WaitForSingleObject(hungup_event,0)==WAIT_OBJECT_0)
417: uart_msr_reg &=~ UART_MSR_DCD;
418: else
419: uart_msr_reg |= UART_MSR_DCD;
420: *data = uart_msr_reg;
421: maybe_yield();
422: /* Clear modem status interrupt pending */
423: deassert_interrupt(UART_IER_MODEM_STATUS);
424: break;
425: case UART_SCRATCH:
426: *data = uart_scratch_reg;
427: break;
428: default:
429: lprintf(LOG_ERR,"UNSUPPORTED register: %u", reg);
430: break;
431: }
432:
433: if(reg!=UART_BASE)
434: lprintf(LOG_DEBUG, "returning 0x%02X", *data);
435: }
436:
437: /* VDD DOS Interface (mainly for FOSSIL driver in dosxtrn.exe) */
438:
439: __declspec(dllexport) void __cdecl VDDDispatch(void)
440: {
441: char str[512];
442: DWORD count;
443: DWORD msgs;
444: int retval;
445: int node_num;
446: BYTE* p;
447: vdd_status_t* status;
448: static DWORD writes;
449: static DWORD bytes_written;
450: static DWORD reads;
451: static DWORD bytes_read;
452: static DWORD inbuf_poll;
453: static DWORD online_poll;
454: static DWORD status_poll;
455: static DWORD vdd_yields;
456: static DWORD vdd_calls;
457: VDD_IO_HANDLERS IOHandlers = { NULL };
458: static VDD_IO_PORTRANGE PortRange;
459:
460: retval=0;
461: node_num=getBH();
462:
463: lprintf(LOG_DEBUG,"VDD_OP: (handle=%d) %d (arg=%X)", getAX(),getBL(),getCX());
464: vdd_calls++;
465:
466: switch(getBL()) {
467:
468: case VDD_OPEN:
469:
470: sscanf("$Revision: 1.38 $", "%*s %s", revision);
471:
472: lprintf(LOG_INFO,"Synchronet Virtual Device Driver, rev %s %s %s"
473: ,revision, __DATE__, __TIME__);
474: #if 0
475: sprintf(str,"sbbsexec%d.log",node_num);
476: fp=fopen(str,"wb");
477: #endif
478:
479: sprintf(str,"\\\\.\\mailslot\\sbbsexec\\wr%d",node_num);
480: rdslot=CreateMailslot(str
481: ,LINEAR_RX_BUFLEN /* Max message size (0=any) */
482: ,MAILSLOT_WAIT_FOREVER /* Read timeout */
483: ,NULL);
484: if(rdslot==INVALID_HANDLE_VALUE) {
485: lprintf(LOG_ERR,"!VDD_OPEN: Error %d opening %s"
486: ,GetLastError(),str);
487: retval=1;
488: break;
489: }
490:
491: sprintf(str,"\\\\.\\mailslot\\sbbsexec\\rd%d",node_num);
492: wrslot=CreateFile(str
493: ,GENERIC_WRITE
494: ,FILE_SHARE_READ
495: ,NULL
496: ,OPEN_EXISTING
497: ,FILE_ATTRIBUTE_NORMAL
498: ,(HANDLE) NULL);
499: if(wrslot==INVALID_HANDLE_VALUE) {
500: lprintf(LOG_ERR,"!VDD_OPEN: Error %d opening %s"
501: ,GetLastError(),str);
502: retval=2;
503: break;
504: }
505:
506: if(RingBufInit(&rdbuf, RINGBUF_SIZE_IN)!=0) {
507: retval=3;
508: break;
509: }
510:
511: sprintf(str,"sbbsexec_hungup%d",node_num);
512: hungup_event=OpenEvent(
513: EVENT_ALL_ACCESS, /* access flag */
514: FALSE, /* inherit flag */
515: str); /* pointer to event-object name */
516: if(hungup_event==NULL) {
517: lprintf(LOG_ERR,"!VDD_OPEN: Error %d opening %s"
518: ,GetLastError(),str);
519: retval=4;
520: break;
521: }
522:
523: sprintf(str,"sbbsexec_hangup%d",node_num);
524: hangup_event=OpenEvent(
525: EVENT_ALL_ACCESS, /* access flag */
526: FALSE, /* inherit flag */
527: str); /* pointer to event-object name */
528: if(hangup_event==NULL) {
529: lprintf(LOG_WARNING,"!VDD_OPEN: Error %d opening %s"
530: ,GetLastError(),str);
531: }
532:
533: status_poll=0;
534: inbuf_poll=0;
535: online_poll=0;
536: yields=0;
537:
538: lprintf(LOG_INFO,"Yield interval: %f milliseconds", yield_interval);
539:
540: if(virtualize_uart) {
541: lprintf(LOG_INFO,"Virtualizing UART (0x%x, IRQ %u)"
542: ,uart_io_base, uart_irq);
543:
544: IOHandlers.inb_handler = uart_rdport;
545: IOHandlers.outb_handler = uart_wrport;
546: PortRange.First=uart_io_base;
547: PortRange.Last=uart_io_base + UART_IO_RANGE;
548:
549: VDDInstallIOHook((HANDLE)getAX(), 1, &PortRange, &IOHandlers);
550:
551: interrupt_event=CreateEvent(NULL,FALSE,FALSE,NULL);
552: InitializeCriticalSection(&interrupt_mutex);
553:
554: _beginthread(interrupt_thread, 0, NULL);
555: }
556:
557: lprintf(LOG_DEBUG,"VDD_OPEN: Opened successfully");
558:
559: _beginthread(input_thread, 0, NULL);
560:
561: retval=0;
562: break;
563:
564: case VDD_CLOSE:
565: lprintf(LOG_INFO,"VDD_CLOSE: rdbuf=%u "
566: "status_poll=%u inbuf_poll=%u online_poll=%u yields=%u vdd_yields=%u vdd_calls=%u"
567: ,RingBufFull(&rdbuf),status_poll,inbuf_poll,online_poll
568: ,yields,vdd_yields,vdd_calls);
569: lprintf(LOG_INFO," read=%u bytes (in %u calls)",bytes_read,reads);
570: lprintf(LOG_INFO," wrote=%u bytes (in %u calls)",bytes_written,writes);
571:
572: if(virtualize_uart) {
573: lprintf(LOG_INFO,"Uninstalling Virtualizaed UART IO Hook");
574: VDDDeInstallIOHook((HANDLE)getAX(), 1, &PortRange);
575: }
576:
577: CloseHandle(rdslot);
578: CloseHandle(wrslot);
579: if(hungup_event!=NULL)
580: CloseHandle(hungup_event);
581: if(hangup_event!=NULL)
582: CloseHandle(hangup_event);
583:
584: #if 0 /* This isn't strictly necessary...
585: and possibly the cause of a NULL dereference in the input_thread */
586: RingBufDispose(&rdbuf);
587: #endif
588: status_poll=0;
589: retval=0;
590:
591: break;
592:
593: case VDD_READ:
594: count = getCX();
595: if(count != 1)
596: lprintf(LOG_DEBUG,"VDD_READ of %d",count);
597: p = (BYTE*) GetVDMPointer((ULONG)((getES() << 16)|getDI())
598: ,count,FALSE);
599: retval=vdd_read(p, count);
600: reads++;
601: bytes_read+=retval;
602: reset_yield();
603: break;
604:
605: case VDD_PEEK:
606: count = getCX();
607: if(count != 1)
608: lprintf(LOG_DEBUG,"VDD_PEEK of %d",count);
609:
610: p = (BYTE*) GetVDMPointer((ULONG)((getES() << 16)|getDI())
611: ,count,FALSE);
612: retval=RingBufPeek(&rdbuf,p,count);
613: reset_yield();
614: break;
615:
616: case VDD_WRITE:
617: count = getCX();
618: if(count != 1)
619: lprintf(LOG_DEBUG,"VDD_WRITE of %d",count);
620: p = (BYTE*) GetVDMPointer((ULONG)((getES() << 16)|getDI())
621: ,count,FALSE);
622: if(!WriteFile(wrslot,p,count,&retval,NULL)) {
623: lprintf(LOG_ERR,"!VDD_WRITE: WriteFile Error %d (size=%d)"
624: ,GetLastError(),retval);
625: retval=0;
626: } else {
627: writes++;
628: bytes_written+=retval;
629: reset_yield();
630: }
631: break;
632:
633: case VDD_STATUS:
634:
635: status_poll++;
636: count = getCX();
637: if(count != sizeof(vdd_status_t)) {
638: lprintf(LOG_DEBUG,"!VDD_STATUS: wrong size (%d!=%d)",count,sizeof(vdd_status_t));
639: retval=sizeof(vdd_status_t);
640: break;
641: }
642: status = (vdd_status_t*) GetVDMPointer((ULONG)((getES() << 16)|getDI())
643: ,count,FALSE);
644:
645: status->inbuf_full=RingBufFull(&rdbuf);
646:
647: /* OUTBUF FULL/SIZE */
648: if(!GetMailslotInfo(
649: wrslot, /* mailslot handle */
650: &status->outbuf_size, /* address of maximum message size */
651: &status->outbuf_full, /* address of size of next message */
652: &msgs, /* address of number of messages */
653: NULL /* address of read time-out */
654: )) {
655: status->outbuf_full=0;
656: status->outbuf_size=DEFAULT_MAX_MSG_SIZE;
657: }
658: if(status->outbuf_full==MAILSLOT_NO_MESSAGE)
659: status->outbuf_full=0;
660: status->outbuf_full*=msgs;
661:
662: /* ONLINE */
663: if(WaitForSingleObject(hungup_event,0)==WAIT_OBJECT_0)
664: status->online=0;
665: else
666: status->online=1;
667:
668: retval=0; /* success */
669: break;
670:
671: case VDD_INBUF_PURGE:
672: RingBufReInit(&rdbuf);
673: retval=0;
674: break;
675:
676: case VDD_OUTBUF_PURGE:
677: lprintf(LOG_WARNING,"!VDD_OUTBUF_PURGE: NOT IMPLEMENTED");
678: retval=0;
679: break;
680:
681: case VDD_INBUF_FULL:
682: retval=RingBufFull(&rdbuf);
683: inbuf_poll++;
684: break;
685:
686: case VDD_INBUF_SIZE:
687: retval=RINGBUF_SIZE_IN;
688: break;
689:
690: case VDD_OUTBUF_FULL:
691: if(!GetMailslotInfo(
692: wrslot, /* mailslot handle */
693: NULL, /* address of maximum message size */
694: &retval, /* address of size of next message */
695: &msgs, /* address of number of messages */
696: NULL /* address of read time-out */
697: ))
698: retval=0;
699: if(retval==MAILSLOT_NO_MESSAGE)
700: retval=0;
701: retval*=msgs;
702: break;
703:
704: case VDD_OUTBUF_SIZE:
705: if(!GetMailslotInfo(
706: wrslot, /* mailslot handle */
707: &retval, /* address of maximum message size */
708: NULL, /* address of size of next message */
709: NULL, /* address of number of messages */
710: NULL /* address of read time-out */
711: ))
712: retval=DEFAULT_MAX_MSG_SIZE;
713: break;
714:
715: case VDD_ONLINE:
716: if(WaitForSingleObject(hungup_event,0)==WAIT_OBJECT_0)
717: retval=0;
718: else
719: retval=1;
720: online_poll++;
721: break;
722:
723: case VDD_YIELD: /* forced yield */
724: vdd_yields++;
725: yield();
726: break;
727:
728: case VDD_MAYBE_YIELD: /* yield if YieldInterval is enabled and expired */
729: maybe_yield();
730: break;
731:
732: case VDD_LOAD_INI_FILE: /* Load and parse settings file */
733: {
734: FILE* fp;
735: char cwd[MAX_PATH+1];
736:
737: /* Load exec/sbbsexec.ini first (setting default values) */
738: count = getCX();
739: p = (BYTE*)GetVDMPointer((ULONG)((getES() << 16)|getDI())
740: ,count,FALSE);
741: iniFileName(ini_fname, sizeof(ini_fname), p, INI_FILENAME);
742: if((fp=fopen(ini_fname,"r"))!=NULL) {
743: ini=iniReadFile(fp);
744: fclose(fp);
745: parse_ini(ROOT_SECTION);
746: }
747:
748: /* Load cwd/sbbsexec.ini second (over-riding default values) */
749: GetCurrentDirectory(sizeof(cwd),cwd);
750: iniFileName(ini_fname, sizeof(ini_fname), cwd, INI_FILENAME);
751: if((fp=fopen(ini_fname,"r"))!=NULL) {
752: ini=iniReadFile(fp);
753: fclose(fp);
754: parse_ini(ROOT_SECTION);
755: }
756: }
757: break;
758:
759: case VDD_LOAD_INI_SECTION: /* Parse (program-specific) sub-section of settings file */
760: count = getCX();
761: p = (BYTE*)GetVDMPointer((ULONG)((getES() << 16)|getDI())
762: ,count,FALSE);
763: parse_ini(p);
764: break;
765:
766: case VDD_DEBUG_OUTPUT: /* Send string to debug output */
767: count = getCX();
768: p = (BYTE*)GetVDMPointer((ULONG)((getES() << 16)|getDI())
769: ,count,FALSE);
770: lputs(LOG_INFO, p);
771: break;
772:
773: case VDD_HANGUP:
774: hangup();
775: break;
776:
777: default:
778: lprintf(LOG_ERR,"!UNKNOWN VDD_OP: %d",getBL());
779: break;
780: }
781: setAX((WORD)retval);
782: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.