1 /*============================================================================
2   socket.c
3 ==============================================================================
4   Implementation of TChanSwitch class: A generic channel switch -- an object
5   that brokers a connection between an HTTP client and server.
6 ============================================================================*/
7 
8 #include <sys/types.h>
9 #include <assert.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 
13 #include "bool.h"
14 #include "int.h"
15 #include "mallocvar.h"
16 #include "xmlrpc-c/util_int.h"
17 #include "xmlrpc-c/abyss.h"
18 #ifdef WIN32
19   #include "socket_win.h"
20 #else
21   #include "socket_unix.h"
22 #endif
23 #include "chanswitch.h"
24 
25 
26 static void
socketOsInit(const char ** const errorP)27 socketOsInit(const char ** const errorP) {
28 
29 #ifdef WIN32
30     SocketWinInit(errorP);
31 #else
32     SocketUnixInit(errorP);
33 #endif
34 }
35 
36 
37 
38 static void
socketOsTerm(void)39 socketOsTerm(void) {
40 
41 #ifdef WIN32
42     SocketWinTerm();
43 #else
44     SocketUnixTerm();
45 #endif
46 }
47 
48 
49 
50 bool SwitchTraceIsActive;
51 
52 void
ChanSwitchInit(const char ** const errorP)53 ChanSwitchInit(const char ** const errorP) {
54 
55     socketOsInit(errorP);
56 
57     if (!*errorP) {
58         SwitchTraceIsActive = (getenv("ABYSS_TRACE_SWITCH") != NULL);
59         if (SwitchTraceIsActive)
60             fprintf(stderr, "Abyss channel switch layer will trace "
61                     "channel connection activity "
62                     "due to ABYSS_TRACE_SWITCH environment variable\n");
63     }
64 }
65 
66 
67 
68 void
ChanSwitchTerm(void)69 ChanSwitchTerm(void) {
70 
71     socketOsTerm();
72 }
73 
74 
75 
76 /* ChanSwitchCreate() is not exported to the Abyss user.  It is meant to
77    be used by an implementation-specific TChanSwitch generator which is
78    exported to the Abyss user, e.g. SwitchCreateUnix() in
79    socket_unix.c
80 
81    The TChanSwitch generator functions are the _only_ user-accessible
82    functions that are particular to an implementation.
83 */
84 
85 static unsigned int const switchSignature = 0x06060A;
86 
87 void
ChanSwitchCreate(const struct TChanSwitchVtbl * const vtblP,void * const implP,TChanSwitch ** const chanSwitchPP)88 ChanSwitchCreate(const struct TChanSwitchVtbl * const vtblP,
89                  void *                         const implP,
90                  TChanSwitch **                 const chanSwitchPP) {
91 
92     TChanSwitch * chanSwitchP;
93 
94     MALLOCVAR(chanSwitchP);
95 
96     if (chanSwitchP) {
97         chanSwitchP->implP     = implP;
98         chanSwitchP->vtbl      = *vtblP;
99         chanSwitchP->signature = switchSignature;
100 
101         if (SwitchTraceIsActive)
102             fprintf(stderr, "Created channel switch %p\n", chanSwitchP);
103 
104         *chanSwitchPP = chanSwitchP;
105     }
106 }
107 
108 
109 
110 void
ChanSwitchDestroy(TChanSwitch * const chanSwitchP)111 ChanSwitchDestroy(TChanSwitch * const chanSwitchP) {
112 
113     if (SwitchTraceIsActive)
114         fprintf(stderr, "Destroying channel switch %p\n", chanSwitchP);
115 
116     assert(chanSwitchP->signature == switchSignature);
117 
118     chanSwitchP->vtbl.destroy(chanSwitchP);
119 
120     chanSwitchP->signature = 0;  /* For debuggability */
121 
122     free(chanSwitchP);
123 }
124 
125 
126 
127 void
ChanSwitchListen(TChanSwitch * const chanSwitchP,uint32_t const backlog,const char ** const errorP)128 ChanSwitchListen(TChanSwitch * const chanSwitchP,
129                  uint32_t      const backlog,
130                  const char ** const errorP) {
131 
132     if (SwitchTraceIsActive)
133         fprintf(stderr, "Channel switch %p listening.\n", chanSwitchP);
134 
135     (*chanSwitchP->vtbl.listen)(chanSwitchP, backlog, errorP);
136 }
137 
138 
139 
140 void
ChanSwitchAccept(TChanSwitch * const chanSwitchP,TChannel ** const channelPP,void ** const channelInfoPP,const char ** const errorP)141 ChanSwitchAccept(TChanSwitch * const chanSwitchP,
142                  TChannel **   const channelPP,
143                  void **       const channelInfoPP,
144                  const char ** const errorP) {
145 
146     if (SwitchTraceIsActive)
147         fprintf(stderr, "Getting a connection from Channel switch %p...\n",
148                 chanSwitchP);
149 
150     (*chanSwitchP->vtbl.accept)(chanSwitchP, channelPP, channelInfoPP, errorP);
151 
152     if (SwitchTraceIsActive)
153         fprintf(stderr, "Got connection from channel switch.  "
154                 "Channel = %p\n", *channelPP);
155 }
156 
157 
158 
159 void
ChanSwitchInterrupt(TChanSwitch * const chanSwitchP)160 ChanSwitchInterrupt(TChanSwitch * const chanSwitchP) {
161 
162     if (SwitchTraceIsActive)
163         fprintf(stderr, "Interrupting wait for a connection "
164                 "by Channel switch %p...\n",
165                 chanSwitchP);
166 
167     (*chanSwitchP->vtbl.interrupt)(chanSwitchP);
168 }
169