d336b77d42f5ec65e9d7fa2f03d8468e514b6a96
[tpg/opendispense2.git] / src / server / main.c
1 /*
2  * OpenDispense 2 
3  * UCC (University [of WA] Computer Club) Electronic Accounting System
4  *
5  * main.c - Initialisation Code
6  *
7  * This file is licenced under the 3-clause BSD Licence. See the file
8  * COPYING for full details.
9  */
10 #include <stdlib.h>
11 #include <stdio.h>
12 #include <string.h>
13 #include <signal.h>
14 #include "common.h"
15 #include <termios.h>
16 #include <unistd.h>
17 #include <sys/stat.h>
18 #include <fcntl.h>
19 #include <stdarg.h>
20 #include <syslog.h>
21 #include <pthread.h>
22 #include "../cokebank.h"
23
24 // === IMPORTS ===
25 extern void     Init_Handlers(void);
26 extern void     Load_Itemlist(void);
27 extern void     Server_Start(void);
28 extern int      gbServer_RunInBackground;
29 extern int      giServer_Port;
30 extern char     *gsItemListFile;
31 extern char     *gsCoke_SerialPort;
32 extern char     *gsSnack_SerialPort;
33 extern char     *gsDoor_SerialPort;
34
35 // === PROTOTYPES ===
36 void    *Periodic_Thread(void *Unused);
37
38 // === GLOBALS ===
39  int    giDebugLevel = 0;
40 char    *gsCokebankPath = "cokebank.db";
41 // - Functions called every 20s (or so)
42 #define ciMaxPeriodics  10
43 struct sPeriodicCall {
44         void    (*Function)(void);
45 }       gaPeriodicCalls[ciMaxPeriodics];
46 pthread_t       gTimerThread;
47
48 // === CODE ===
49 void sigint_handler()
50 {
51         exit(0);
52 }
53
54 void PrintUsage(const char *progname)
55 {
56         fprintf(stderr, "Usage: %s\n", progname);
57         fprintf(stderr, "  -p    Set server port (default 11020)\n");
58         fprintf(stderr, "  -d    Set debug level (0 - 2, default 0)\n");
59         fprintf(stderr, "  --itemsfile\n");
60         fprintf(stderr, "        Set debug level (0 - 2, default 0)\n");
61         fprintf(stderr, "  --cokeport\n");
62         fprintf(stderr, "        Coke machine serial port (Default \"/dev/ttyS0\")\n");
63         fprintf(stderr, "  --doorport\n");
64         fprintf(stderr, "        Door modem/relay serial port (Default \"/dev/ttyS3\")\n");
65         fprintf(stderr, "  --cokebank\n");
66         fprintf(stderr, "        Coke bank database file (Default \"cokebank.db\")\n");
67         fprintf(stderr, "  --[dont-]daemonise\n");
68         fprintf(stderr, "        Run (or explicitly don't) the server disconnected from the terminal\n");
69 }
70
71 int main(int argc, char *argv[])
72 {
73          int    i;
74         
75         // Parse Arguments
76         for( i = 1; i < argc; i++ )
77         {
78                 char    *arg = argv[i];
79                 if( arg[0] == '-' && arg[1] != '-')
80                 {
81                         switch(arg[1])
82                         {
83                         case 'p':
84                                 if( i + 1 >= argc )     return -1;
85                                 giServer_Port = atoi(argv[++i]);
86                                 break;
87                         case 'd':
88                                 if( i + 1 >= argc )     return -1;
89                                 giDebugLevel = atoi(argv[++i]);
90                                 break;
91                         case 'D':
92                                 gbServer_RunInBackground = 1;
93                                 return -1;
94                         default:
95                                 // Usage Error?
96                                 PrintUsage(argv[0]);
97                                 return -1;
98                         }
99                 }
100                 else if( arg[0] == '-' && arg[1] == '-' ) {
101                         if( strcmp(arg, "--itemsfile") == 0 ) {
102                                 if( i + 1 >= argc )     return -1;
103                                 gsItemListFile = argv[++i];
104                         }
105                         else if( strcmp(arg, "--cokeport") == 0 ) {
106                                 if( i + 1 >= argc )     return -1;
107                                 gsCoke_SerialPort = argv[++i];
108                         }
109                         else if( strcmp(arg, "--snackport") == 0 ) {
110                                 if( i + 1 >= argc )     return -1;
111                                 gsSnack_SerialPort = argv[++i];
112                         }
113                         else if( strcmp(arg, "--doorport") == 0 ) {
114                                 if( i + 1 >= argc )     return -1;
115                                 gsDoor_SerialPort = argv[++i];
116                         }
117                         else if( strcmp(arg, "--cokebank") == 0 ) {
118                                 if( i + 1 >= argc )     return -1;
119                                 gsCokebankPath = argv[++i];
120                         }
121                         else if( strcmp(arg, "--daemonise") == 0 ) {
122                                 gbServer_RunInBackground = 1;
123                         }
124                         else if( strcmp(arg, "--dont-daemonise") == 0 ) {
125                                 gbServer_RunInBackground = 0;
126                         }
127                         else {
128                                 // Usage error?
129                                 PrintUsage(argv[0]);
130                                 return -1;
131                         }
132                 }
133                 else {
134                         // Usage Error?
135                         PrintUsage(argv[0]);
136                         return -1;
137                 }
138         }
139         
140         signal(SIGINT, sigint_handler);
141         signal(SIGTERM, sigint_handler);
142         
143         openlog("odispense2", 0, LOG_LOCAL4);
144         
145         if( Bank_Initialise(gsCokebankPath) )
146                 return -1;
147
148         Init_Handlers();
149
150         Load_Itemlist();
151         
152         Server_Start();
153         
154         pthread_kill(gTimerThread, SIGKILL);
155
156         return 0;
157 }
158
159 void *Periodic_Thread(void *Unused)
160 {
161          int    i;
162         Unused = NULL;  // quiet, gcc
163         
164         for( ;; )
165         {
166                 sleep(10);      // Sleep for a while
167 //              printf("Periodic firing\n");
168                 for( i = 0; i < ciMaxPeriodics; i ++ )
169                 {
170                         if( gaPeriodicCalls[i].Function )
171                                 gaPeriodicCalls[i].Function();
172                 }
173         }
174         return NULL;
175 }
176
177 void StartPeriodicThread(void)
178 {
179         pthread_create( &gTimerThread, NULL, Periodic_Thread, NULL );
180 }
181
182 void AddPeriodicFunction(void (*Fcn)(void))
183 {
184         int i;
185         for( i = 0; i < ciMaxPeriodics; i ++ )
186         {
187                 if( gaPeriodicCalls[i].Function )       continue;
188                 gaPeriodicCalls[i].Function = Fcn;
189                 return ;
190         }
191         
192         fprintf(stderr, "Error: No space for %p in periodic list\n", Fcn);
193 }
194
195 int RunRegex(regex_t *regex, const char *string, int nMatches, regmatch_t *matches, const char *errorMessage)
196 {
197          int    ret;
198         
199         ret = regexec(regex, string, nMatches, matches, 0);
200         if( ret == REG_NOMATCH ) {
201                 return -1;
202         }
203         if( ret ) {
204                 size_t  len = regerror(ret, regex, NULL, 0);
205                 char    errorStr[len];
206                 regerror(ret, regex, errorStr, len);
207                 printf("string = '%s'\n", string);
208                 fprintf(stderr, "%s\n%s", errorMessage, errorStr);
209                 exit(-1);
210         }
211         
212         return ret;
213 }
214
215 void CompileRegex(regex_t *regex, const char *pattern, int flags)
216 {
217          int    ret = regcomp(regex, pattern, flags);
218         if( ret ) {
219                 size_t  len = regerror(ret, regex, NULL, 0);
220                 char    errorStr[len];
221                 regerror(ret, regex, errorStr, len);
222                 fprintf(stderr, "Regex compilation failed - %s\n", errorStr);
223                 exit(-1);
224         }
225 }
226
227 // Serial helper
228 int InitSerial(const char *File, int BaudRate)
229 {
230         struct termios  info;
231          int    baud;
232          int    fd;
233         
234         fd = open(File, O_RDWR | O_NOCTTY | O_NONBLOCK);
235         if( fd == -1 )  return -1;
236         
237         switch(BaudRate)
238         {
239         case 9600:      baud = B9600;   break;
240         default:        close(fd);      return -1;
241         }
242         
243         info.c_lflag = 0;       // Non-Canoical, No Echo
244         info.c_cflag = baud | CS8 | CLOCAL | CREAD;     // baud, 8N1
245         info.c_iflag = IGNCR;   // Ignore \r
246         info.c_oflag = 0;       // ???
247         cfsetspeed(&info, baud);
248         info.c_cc[VTIME] = 0;   // No time limit
249         info.c_cc[VMIN] = 1;    // Block until 1 char
250         
251         tcflush(fd, TCIFLUSH);
252         tcsetattr(fd, TCSANOW, &info);
253         
254         return fd;
255 }
256
257
258 /**
259  * \brief Create a formatted heap string
260  */
261 char *mkstr(const char *Format, ...)
262 {
263         va_list args;
264          int    len;
265         char    *ret;
266
267         va_start(args, Format);
268         len = vsnprintf(NULL, 0, Format, args);
269         va_end(args);
270
271         ret = malloc( len + 1 );
272         if(!ret)        return NULL;
273
274         va_start(args, Format);
275         vsprintf(ret, Format, args);
276         va_end(args);
277         
278         return ret;
279 }
280

UCC git Repository :: git.ucc.asn.au