2 openisis - an open implementation of the CDS/ISIS database
3 Version 0.8.x (patchlevel see file Version)
4 Copyright (C) 2001-2003 by Erik Grziwotz, erik@openisis.org
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with this library; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 see README for more information
24 $Id: lcli.c,v 1.13 2003/05/15 19:17:17 mawag Exp $
25 OpenIsis client side of communication
29 #include <sys/types.h>
30 #include <sys/socket.h> /* socket etc */
31 #include <netinet/in.h> /* IPPROTO_TCP, htons */
32 #include <netdb.h> /* gethostbyname */
45 gcc -D_MAIN_ -I. -Lsto lcli.c -lopenisis && ./a.out 111 `find .`
46 gcc -D_MAIN_ -DWIN32 -I. lcli.c win/libopenisis.a /mingw/lib/libwsock32.a
49 #define LF 10 /* LineFeed a.k.a. newline - '\n' isn't really well defined */
50 #define TAB 9 /* horizontal, that is */
51 #define VT 11 /* vertical, used as newline replacement */
53 #define STAT_CONT 0x01 /* not at beginning of line */
54 #define STAT_BIN 0x10 /* binary mode */
57 * @return done or -err
59 int cliPlain (Ios *s, int *stat, Rec **rec) {
61 int l = s->b.fill - s->b.done;
62 unsigned char *b = s->b.c + s->b.done;
63 unsigned char *end = b+l, *v, *p;
64 if ( ! l ) { /* EOF: done */
65 if ( ! (STAT_CONT & *stat) ) /* ok */
67 /* last field wasn't closed by LF */
68 return sMsg (ERR_INVAL, "cliPlain(%d): no EOL", LIO_FD & s->file);
70 if ( STAT_CONT & *stat )
71 RSPACE( *rec, l, !0 );
75 switch ( STAT_CONT & *stat ) {
76 case 0: /* at beginning of line -- start new field */
77 if ( LF == *b ) /* empty line */
79 if ( TAB != *b || ! *rec || ! (*rec)->len ) {
80 RADD( *rec, 0,0,end-b, !0 );
82 else { /* binary mode continuation line */
84 if ( !(STAT_BIN & *stat)) {
85 sMsg( LOG_INFO, "cliPlain(%d): detected binary mode",
89 RSPACE( *rec, end-b, !0 );
94 case STAT_CONT: /* add to last field */
95 f = (*rec)->field + (*rec)->len-1;
96 v = (unsigned char*)f->val;
102 if ( STAT_BIN & *stat ) {
103 for ( ; b<end && LF != (*p = *b++); p++ )
106 for ( ; b<end && LF != (*p = *b++); p++ )
107 if ( VT == *p ) /* convert VTABs */
108 *p = LF; /* back to newlines */
110 (*rec)->used += (p - v) - f->len;
113 int ret = a2il( f->val, f->len, &f->tag );
115 if ( ret < f->len && TAB == v[ret] )
118 memmove( v, v+ret, f->len - ret );
123 sMsg (LOG_VERBOSE, "cliPlain(%d): fld[%2d] %3d = '%.*s'",
124 LIO_FD & s->file, (*rec)->len-1, f->tag, f->len, f->val);
130 Rec* cliRead (CliChnl *ch) {
135 if (!ch || 0 > ch->sd) {
138 memset (&str, 0, sizeof (Ios));
139 str.file = ch->sd | LIO_IN;
145 str.b.done = str.b.fill;
146 rt = ioStdio (&str, LIO_SFILL);
152 if (!(LIO_IN & str.file)) {
157 rt = cliPlain (&str, &stat, &rec);
165 log_rec (LOG_VERBOSE, rec, "cliRead(%d): ", 0);
166 sMsg (LOG_INFO, "cliRead(%d): read #flds %d",
167 ch->sd, (rec ? rec->len : -1));
173 int cliWrite (CliChnl *ch, Rec *rec) {
176 int fd, len, sl, rl, rt;
177 if (!ch || 0 > ch->sd) {
181 if (!rec || !rec->len) {
185 b = rSerA (rec, buf, &len);
187 return sMsg (ERR_NOMEM, "cliWrite(%d): write (%d)", ch->sd, rec->used);
189 fd = ch->sd | LIO_OUT;
190 for (sl = rt = errno = 0, rl = len; rl; sl += rt, rl -= rt) {
191 rt = lio_write (&fd, b + sl, (unsigned)rl);
194 if (!(LIO_OUT & fd)) {
204 return sMsg (ERR_IO, "cliWrite(%d): write (%d) = %d(%d)",
207 sMsg (LOG_INFO, "cliWrite(%d): wrote %d,%d", ch->sd, rec->len, len);
211 int cliConnect (CliChnl *ch, const char *hname, int port) {
213 return sMsg (ERR_TRASH, "cliConnect: operation not supported");
215 struct sockaddr_in addr;
216 struct hostent *hostp;
219 return sMsg (ERR_IDIOT, "cliConnect: null channel");
221 memset (ch, 0, sizeof (CliChnl));
222 rt = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP);
225 return sMsg (ERR_IO, "cliConnect: cannot create socket: %d", errno);
228 memset (&addr, 0, sizeof (addr));
230 hostp = gethostbyname (hname);
233 return sMsg (ERR_INVAL, "cliConnect: unknown host <%s>: %d",
236 addr.sin_family = hostp->h_addrtype; /* already network-byte-order */
237 addr.sin_addr.s_addr = *(long*)(*(hostp->h_addr_list)); /* dto */
240 addr.sin_family = AF_INET;
241 addr.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
243 addr.sin_port = htons (port);
244 rt = connect (ch->sd, &addr, sizeof (addr));
247 return sMsg (ERR_IO, "cliConnect: cannot connect to %s:%d: %d",
248 (hname ? hname : "localhost"), port, errno);
254 void cliClose (CliChnl *ch) {
255 if (ch && 0 <= ch->sd) {
261 /* -----------------------------------------------------------------------
266 #include <stdio.h> /* printf */
267 #include <stdlib.h> /* atoi */
268 #include <string.h> /* strerror */
269 #include "luti.h" /* log_rec */
271 void cmp (Rec *in, Rec *out) {
276 for (j = k = 0, F1 = in->field, F2 = out->field; l2 > k; ++k, ++F2) {
281 printf ("ERR too many answers %d %d\n", j, k);
282 log_rec (0, in, "ERR IN ", 0);
283 log_rec (0, out, "ERR OUT ", 0);
286 if (F1->tag != F2->tag) {
287 printf ("ERR tag %d mismatch %d %d\n", j, F1->tag, F2->tag);
288 log_rec (0, in, "ERR IN ", 0);
289 log_rec (0, out, "ERR OUT ", 0);
292 if (F1->len != F2->len) {
293 printf ("ERR len %d mismatch %d %d\n", j, F1->tag, F2->tag);
294 log_rec (0, in, "ERR IN ", 0);
295 log_rec (0, out, "ERR OUT ", 0);
298 if (memcmp (F1->val, F2->val, F1->len)) {
299 printf ("ERR val %d mismatch\n", j);
300 log_rec (0, in, "ERR IN ", 0);
301 log_rec (0, out, "ERR OUT ", 0);
309 int loop (CliChnl *ch, Rec *demo, int fail) {
312 rt = cliWrite (ch, demo);
314 printf ("%s write %d %s\n", (fail ? "ERR":"WARN"),
315 ch->err, strerror (ch->err));
323 printf ("%s read %d %s\n", (fail ? "ERR":"WARN"),
324 ch->err, strerror (ch->err));
335 int main (int argc, char **argv) {
343 for (j = 1; argc > j; ++j) {
344 if (*argv[j] == '-') {
345 if (argv[j][1] == 'h') {
349 if (argv[j][1] == 'p') {
350 port = atoi (argv[j] + 2);
354 num = atoi (argv[j]);
362 for (j = argc; 0 <= --j; ) {
363 RADDS (demo, j, argv[j], !0);
369 if (cliConnect (&ch, hname, port)) {
370 printf ("ERR connect %d %s\n", ch.err, strerror (ch.err));
376 if (loop (&ch, demo, 0)) {
378 if (cliConnect (&ch, hname, port)) {
379 printf ("ERR reconnect %d %s\n", ch.err, strerror (ch.err));
382 loop (&ch, demo, !0);
388 printf ("loop %d ...\n", j);