1 Commits

19 changed files with 2252 additions and 1742 deletions

View File

@@ -31,7 +31,11 @@ libsam3-tests: ${TEST_OBJS} ${LIB}
${CC} $^ -o $@ ${CC} $^ -o $@
clean: clean:
rm -f libsam3-tests ${LIB} ${OBJS} rm -f libsam3-tests ${LIB} ${OBJS} examples/sam3/samtest
%.o: %.c Makefile %.o: %.c Makefile
${CC} ${CFLAGS} -c $< -o $@ ${CC} ${CFLAGS} -c $< -o $@
fmt:
find . -name '*.c' -exec clang-format -i {} \;
find . -name '*.h' -exec clang-format -i {} \;

View File

@@ -4,7 +4,8 @@
* To Public License, Version 2, as published by Sam Hocevar. See * To Public License, Version 2, as published by Sam Hocevar. See
* http://sam.zoy.org/wtfpl/COPYING for more details. * http://sam.zoy.org/wtfpl/COPYING for more details.
* *
* I2P-Bote: 5m77dFKGEq6~7jgtrfw56q3t~SmfwZubmGdyOLQOPoPp8MYwsZ~pfUCwud6LB1EmFxkm4C3CGlzq-hVs9WnhUV * I2P-Bote:
* 5m77dFKGEq6~7jgtrfw56q3t~SmfwZubmGdyOLQOPoPp8MYwsZ~pfUCwud6LB1EmFxkm4C3CGlzq-hVs9WnhUV
* we are the Borg. */ * we are the Borg. */
#include <errno.h> #include <errno.h>
#include <stdio.h> #include <stdio.h>
@@ -14,23 +15,20 @@
#include "../libsam3/libsam3.h" #include "../libsam3/libsam3.h"
// comment the following if you don't want to stress UDP with 'big' datagram // comment the following if you don't want to stress UDP with 'big' datagram
// seems that up to 32000 bytes can be used for localhost // seems that up to 32000 bytes can be used for localhost
// note that we need 516+6+? bytes for header; lets reserve 1024 bytes for it // note that we need 516+6+? bytes for header; lets reserve 1024 bytes for it
#define BIG (32000-1024) #define BIG (32000 - 1024)
#define KEYFILE "dgrams.key"
#define KEYFILE "dgrams.key" int main(int argc, char *argv[]) {
int main (int argc, char *argv[]) {
Sam3Session ses; Sam3Session ses;
char buf[1024]; char buf[1024];
char destkey[517] = {0}; // 516 chars + \0 char destkey[517] = {0}; // 516 chars + \0
int sz; int sz;
// //
//libsam3_debug = 1; libsam3_debug = 1;
// //
if (argc < 2) { if (argc < 2) {
FILE *fl = fopen(KEYFILE, "rb"); FILE *fl = fopen(KEYFILE, "rb");
@@ -55,7 +53,9 @@ int main (int argc, char *argv[]) {
ok: ok:
printf("creating session...\n"); printf("creating session...\n");
/* create TRANSIENT session with temporary disposible destination */ /* create TRANSIENT session with temporary disposible destination */
if (sam3CreateSession(&ses, SAM3_HOST_DEFAULT, SAM3_PORT_DEFAULT, SAM3_DESTINATION_TRANSIENT, SAM3_SESSION_DGRAM, NULL) < 0) { if (sam3CreateSession(&ses, SAM3_HOST_DEFAULT, SAM3_PORT_DEFAULT,
SAM3_DESTINATION_TRANSIENT, SAM3_SESSION_DGRAM, 4,
NULL) < 0) {
fprintf(stderr, "FATAL: can't create session\n"); fprintf(stderr, "FATAL: can't create session\n");
return 1; return 1;
} }
@@ -66,7 +66,7 @@ ok:
goto error; goto error;
} }
/** receive reply */ /** receive reply */
if ((sz = sam3DatagramReceive(&ses, buf, sizeof(buf)-1)) < 0) { if ((sz = sam3DatagramReceive(&ses, buf, sizeof(buf) - 1)) < 0) {
fprintf(stderr, "ERROR: %s\n", ses.error); fprintf(stderr, "ERROR: %s\n", ses.error);
goto error; goto error;
} }
@@ -76,16 +76,16 @@ ok:
// //
#ifdef BIG #ifdef BIG
{ {
char *big = calloc(BIG+1024, sizeof(char)); char *big = calloc(BIG + 1024, sizeof(char));
/** generate random string */ /** generate random string */
sam3GenChannelName(big, BIG+1023, BIG+1023); sam3GenChannelName(big, BIG + 1023, BIG + 1023);
printf("sending BIG datagram...\n"); printf("sending BIG datagram...\n");
if (sam3DatagramSend(&ses, destkey, big, BIG) < 0) { if (sam3DatagramSend(&ses, destkey, big, BIG) < 0) {
free(big); free(big);
fprintf(stderr, "ERROR: %s\n", ses.error); fprintf(stderr, "ERROR: %s\n", ses.error);
goto error; goto error;
} }
if ((sz = sam3DatagramReceive(&ses, big, BIG+512)) < 0) { if ((sz = sam3DatagramReceive(&ses, big, BIG + 512)) < 0) {
free(big); free(big);
fprintf(stderr, "ERROR: %s\n", ses.error); fprintf(stderr, "ERROR: %s\n", ses.error);
goto error; goto error;
@@ -101,7 +101,7 @@ ok:
fprintf(stderr, "ERROR: %s\n", ses.error); fprintf(stderr, "ERROR: %s\n", ses.error);
goto error; goto error;
} }
if ((sz = sam3DatagramReceive(&ses, buf, sizeof(buf)-1)) < 0) { if ((sz = sam3DatagramReceive(&ses, buf, sizeof(buf) - 1)) < 0) {
fprintf(stderr, "ERROR: %s\n", ses.error); fprintf(stderr, "ERROR: %s\n", ses.error);
goto error; goto error;
} }

View File

@@ -4,7 +4,8 @@
* To Public License, Version 2, as published by Sam Hocevar. See * To Public License, Version 2, as published by Sam Hocevar. See
* http://sam.zoy.org/wtfpl/COPYING for more details. * http://sam.zoy.org/wtfpl/COPYING for more details.
* *
* I2P-Bote: 5m77dFKGEq6~7jgtrfw56q3t~SmfwZubmGdyOLQOPoPp8MYwsZ~pfUCwud6LB1EmFxkm4C3CGlzq-hVs9WnhUV * I2P-Bote:
* 5m77dFKGEq6~7jgtrfw56q3t~SmfwZubmGdyOLQOPoPp8MYwsZ~pfUCwud6LB1EmFxkm4C3CGlzq-hVs9WnhUV
* we are the Borg. */ * we are the Borg. */
#include <errno.h> #include <errno.h>
#include <stdio.h> #include <stdio.h>
@@ -14,31 +15,28 @@
#include "../libsam3/libsam3.h" #include "../libsam3/libsam3.h"
#define KEYFILE "dgrams.key"
#define KEYFILE "dgrams.key" int main(int argc, char *argv[]) {
int main (int argc, char *argv[]) {
Sam3Session ses; Sam3Session ses;
char privkey[1024], pubkey[1024], buf[33*1024]; char privkey[1024], pubkey[1024], buf[33 * 1024];
/** quit command */ /** quit command */
const char * quitstr = "quit"; const char *quitstr = "quit";
const size_t quitlen = strlen(quistr); const size_t quitlen = strlen(quitstr);
/** reply response */ /** reply response */
const char * replystr = "reply: "; const char *replystr = "reply: ";
const size_t replylen = strlen(replystr); const size_t replylen = strlen(replystr);
FILE *fl; FILE *fl;
// //
//libsam3_debug = 1; libsam3_debug = 1;
// //
/** generate new destination keypair */ /** generate new destination keypair */
printf("generating keys...\n"); printf("generating keys...\n");
if (sam3GenerateKeys(&ses, SAM3_HOST_DEFAULT, SAM3_PORT_DEFAULT) < 0) { if (sam3GenerateKeys(&ses, SAM3_HOST_DEFAULT, SAM3_PORT_DEFAULT, 4) < 0) {
fprintf(stderr, "FATAL: can't generate keys\n"); fprintf(stderr, "FATAL: can't generate keys\n");
return 1; return 1;
} }
@@ -47,7 +45,8 @@ int main (int argc, char *argv[]) {
strncpy(privkey, ses.privkey, sizeof(privkey)); strncpy(privkey, ses.privkey, sizeof(privkey));
/** create sam session */ /** create sam session */
printf("creating session...\n"); printf("creating session...\n");
if (sam3CreateSession(&ses, SAM3_HOST_DEFAULT, SAM3_PORT_DEFAULT, privkey, SAM3_SESSION_DGRAM, NULL) < 0) { if (sam3CreateSession(&ses, SAM3_HOST_DEFAULT, SAM3_PORT_DEFAULT, privkey,
SAM3_SESSION_DGRAM, 5, NULL) < 0) {
fprintf(stderr, "FATAL: can't create session\n"); fprintf(stderr, "FATAL: can't create session\n");
return 1; return 1;
} }
@@ -70,12 +69,12 @@ int main (int argc, char *argv[]) {
printf("starting main loop...\n"); printf("starting main loop...\n");
for (;;) { for (;;) {
/** save replylen bytes for out reply at begining */ /** save replylen bytes for out reply at begining */
char * datagramBuf = buf + replylen; char *datagramBuf = buf + replylen;
const size_t datagramMaxLen = sizeof(buf) - replyLen; const size_t datagramMaxLen = sizeof(buf) - replylen;
int sz, isquit; int sz, isquit;
printf("waiting for datagram...\n"); printf("waiting for datagram...\n");
/** blocks until we get a UDP packet */ /** blocks until we get a UDP packet */
if ((sz = sam3DatagramReceive(&ses, datagramBuf, datagarmMaxLen) < 0)) { if ((sz = sam3DatagramReceive(&ses, datagramBuf, datagramMaxLen) < 0)) {
fprintf(stderr, "ERROR: %s\n", ses.error); fprintf(stderr, "ERROR: %s\n", ses.error);
goto error; goto error;
} }
@@ -89,12 +88,13 @@ int main (int argc, char *argv[]) {
isquit = (sz == quitlen && memcmp(datagramBuf, quitstr, quitlen) == 0); isquit = (sz == quitlen && memcmp(datagramBuf, quitstr, quitlen) == 0);
/** echo datagram back to sender with "reply: " at the beginning */ /** echo datagram back to sender with "reply: " at the beginning */
memcpy(buf, replystr, replylen); memcpy(buf, replystr, replylen);
if (sam3DatagramSend(&ses, ses.destkey, buf, sz+replylen) < 0) { if (sam3DatagramSend(&ses, ses.destkey, buf, sz + replylen) < 0) {
fprintf(stderr, "ERROR: %s\n", ses.error); fprintf(stderr, "ERROR: %s\n", ses.error);
goto error; goto error;
} }
/** if we got a quit command wait for 10 seconds and break out of the mainloop */ /** if we got a quit command wait for 10 seconds and break out of the
* mainloop */
if (isquit) { if (isquit) {
printf("shutting down...\n"); printf("shutting down...\n");
sleep(10); /* let dgram reach it's destination */ sleep(10); /* let dgram reach it's destination */

View File

@@ -4,7 +4,8 @@
* To Public License, Version 2, as published by Sam Hocevar. See * To Public License, Version 2, as published by Sam Hocevar. See
* http://sam.zoy.org/wtfpl/COPYING for more details. * http://sam.zoy.org/wtfpl/COPYING for more details.
* *
* I2P-Bote: 5m77dFKGEq6~7jgtrfw56q3t~SmfwZubmGdyOLQOPoPp8MYwsZ~pfUCwud6LB1EmFxkm4C3CGlzq-hVs9WnhUV * I2P-Bote:
* 5m77dFKGEq6~7jgtrfw56q3t~SmfwZubmGdyOLQOPoPp8MYwsZ~pfUCwud6LB1EmFxkm4C3CGlzq-hVs9WnhUV
* we are the Borg. */ * we are the Borg. */
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
@@ -13,19 +14,25 @@
#include "../libsam3/libsam3.h" #include "../libsam3/libsam3.h"
int main(int argc, char *argv[]) {
int main (int argc, char *argv[]) {
Sam3Session ses; Sam3Session ses;
// //
//
libsam3_debug = 1;
//
if (argc < 2) { if (argc < 2) {
printf("usage: %s name [name...]\n", argv[0]); printf("usage: %s name [name...]\n", argv[0]);
return 1; return 1;
} }
/** for each name in arguments ... */ /** for each name in arguments ... */
for (int n = 1; n < argc; ++n) { for (int n = 1; n < argc; ++n) {
fprintf(stdout, "%s ... ", argv[n]); fflush(stdout); if (!getenv("I2P_LOOKUP_QUIET")) {
fprintf(stdout, "%s ... ", argv[n]);
fflush(stdout);
}
/** do oneshot name lookup */ /** do oneshot name lookup */
if (sam3NameLookup(&ses, SAM3_HOST_DEFAULT, SAM3_PORT_DEFAULT, argv[n]) >= 0) { if (sam3NameLookup(&ses, SAM3_HOST_DEFAULT, SAM3_PORT_DEFAULT, argv[n]) >=
0) {
fprintf(stdout, "%s\n\n", ses.destkey); fprintf(stdout, "%s\n\n", ses.destkey);
} else { } else {
fprintf(stdout, "FAILED [%s]\n", ses.error); fprintf(stdout, "FAILED [%s]\n", ses.error);

View File

@@ -4,7 +4,8 @@
* To Public License, Version 2, as published by Sam Hocevar. See * To Public License, Version 2, as published by Sam Hocevar. See
* http://sam.zoy.org/wtfpl/COPYING for more details. * http://sam.zoy.org/wtfpl/COPYING for more details.
* *
* I2P-Bote: 5m77dFKGEq6~7jgtrfw56q3t~SmfwZubmGdyOLQOPoPp8MYwsZ~pfUCwud6LB1EmFxkm4C3CGlzq-hVs9WnhUV * I2P-Bote:
* 5m77dFKGEq6~7jgtrfw56q3t~SmfwZubmGdyOLQOPoPp8MYwsZ~pfUCwud6LB1EmFxkm4C3CGlzq-hVs9WnhUV
* we are the Borg. */ * we are the Borg. */
#include <errno.h> #include <errno.h>
#include <stdio.h> #include <stdio.h>
@@ -14,19 +15,25 @@
#include "../libsam3/libsam3.h" #include "../libsam3/libsam3.h"
int main(int argc, char *argv[]) {
int main (int argc, char *argv[]) {
int fd; int fd;
SAMFieldList *rep = NULL; SAMFieldList *rep = NULL;
const char *v; const char *v;
// //
if ((fd = sam3Handshake(NULL, 0, NULL)) < 0) return 1; libsam3_debug = 1;
// //
if (sam3tcpPrintf(fd, "DEST GENERATE\n") < 0) goto error; //
if ((fd = sam3Handshake(NULL, 0, NULL)) < 0)
return 1;
//
if (sam3tcpPrintf(fd, "DEST GENERATE\n") < 0)
goto error;
rep = sam3ReadReply(fd); rep = sam3ReadReply(fd);
//sam3DumpFieldList(rep); // sam3DumpFieldList(rep);
if (!sam3IsGoodReply(rep, "DEST", "REPLY", "PUB", NULL)) goto error; if (!sam3IsGoodReply(rep, "DEST", "REPLY", "PUB", NULL))
if (!sam3IsGoodReply(rep, "DEST", "REPLY", "PRIV", NULL)) goto error; goto error;
if (!sam3IsGoodReply(rep, "DEST", "REPLY", "PRIV", NULL))
goto error;
v = sam3FindField(rep, "PUB"); v = sam3FindField(rep, "PUB");
printf("PUB KEY\n=======\n%s\n", v); printf("PUB KEY\n=======\n%s\n", v);
v = sam3FindField(rep, "PRIV"); v = sam3FindField(rep, "PRIV");

View File

@@ -4,7 +4,8 @@
* To Public License, Version 2, as published by Sam Hocevar. See * To Public License, Version 2, as published by Sam Hocevar. See
* http://sam.zoy.org/wtfpl/COPYING for more details. * http://sam.zoy.org/wtfpl/COPYING for more details.
* *
* I2P-Bote: 5m77dFKGEq6~7jgtrfw56q3t~SmfwZubmGdyOLQOPoPp8MYwsZ~pfUCwud6LB1EmFxkm4C3CGlzq-hVs9WnhUV * I2P-Bote:
* 5m77dFKGEq6~7jgtrfw56q3t~SmfwZubmGdyOLQOPoPp8MYwsZ~pfUCwud6LB1EmFxkm4C3CGlzq-hVs9WnhUV
* we are the Borg. */ * we are the Borg. */
#include <errno.h> #include <errno.h>
#include <stdio.h> #include <stdio.h>
@@ -14,16 +15,14 @@
#include "../libsam3/libsam3.h" #include "../libsam3/libsam3.h"
#define KEYFILE "streams.key"
#define KEYFILE "streams.key" int main(int argc, char *argv[]) {
int main (int argc, char *argv[]) {
Sam3Session ses; Sam3Session ses;
Sam3Connection *conn; Sam3Connection *conn;
char cmd[1024], destkey[517]; // 516 chars + \0 char cmd[1024], destkey[617]; // 616 chars + \0
// //
//libsam3_debug = 1; libsam3_debug = 1;
// //
memset(destkey, 0, sizeof(destkey)); memset(destkey, 0, sizeof(destkey));
// //
@@ -31,17 +30,18 @@ int main (int argc, char *argv[]) {
FILE *fl = fopen(KEYFILE, "rb"); FILE *fl = fopen(KEYFILE, "rb");
// //
if (fl != NULL) { if (fl != NULL) {
if (fread(destkey, 516, 1, fl) == 1) { if (fread(destkey, 616, 1, fl) == 1) {
fclose(fl); fclose(fl);
goto ok; goto ok;
} }
fclose(fl); fclose(fl);
} }
printf("usage: dgramc PUBKEY\n"); printf("usage: streamc PUBKEY\n");
return 1; return 1;
} else { } else {
if (strlen(argv[1]) != 516) { if (!sam3CheckValidKeyLength(argv[1])) {
fprintf(stderr, "FATAL: invalid key length!\n"); fprintf(stderr, "FATAL: invalid key length! %s %lu\n", argv[1],
strlen(argv[1]));
return 1; return 1;
} }
strcpy(destkey, argv[1]); strcpy(destkey, argv[1]);
@@ -50,7 +50,9 @@ int main (int argc, char *argv[]) {
ok: ok:
printf("creating session...\n"); printf("creating session...\n");
// create TRANSIENT session // create TRANSIENT session
if (sam3CreateSession(&ses, SAM3_HOST_DEFAULT, SAM3_PORT_DEFAULT, SAM3_DESTINATION_TRANSIENT, SAM3_SESSION_STREAM, NULL) < 0) { if (sam3CreateSession(&ses, SAM3_HOST_DEFAULT, SAM3_PORT_DEFAULT,
SAM3_DESTINATION_TRANSIENT, SAM3_SESSION_STREAM, 4,
NULL) < 0) {
fprintf(stderr, "FATAL: can't create session\n"); fprintf(stderr, "FATAL: can't create session\n");
return 1; return 1;
} }
@@ -64,12 +66,15 @@ ok:
// //
// now waiting for incoming connection // now waiting for incoming connection
printf("sending test command...\n"); printf("sending test command...\n");
if (sam3tcpPrintf(conn->fd, "test\n") < 0) goto error; if (sam3tcpPrintf(conn->fd, "test\n") < 0)
if (sam3tcpReceiveStr(conn->fd, cmd, sizeof(cmd)) < 0) goto error; goto error;
if (sam3tcpReceiveStr(conn->fd, cmd, sizeof(cmd)) < 0)
goto error;
printf("echo: %s\n", cmd); printf("echo: %s\n", cmd);
// //
printf("sending quit command...\n"); printf("sending quit command...\n");
if (sam3tcpPrintf(conn->fd, "quit\n") < 0) goto error; if (sam3tcpPrintf(conn->fd, "quit\n") < 0)
goto error;
// //
sam3CloseConnection(conn); sam3CloseConnection(conn);
sam3CloseSession(&ses); sam3CloseSession(&ses);

View File

@@ -4,7 +4,8 @@
* To Public License, Version 2, as published by Sam Hocevar. See * To Public License, Version 2, as published by Sam Hocevar. See
* http://sam.zoy.org/wtfpl/COPYING for more details. * http://sam.zoy.org/wtfpl/COPYING for more details.
* *
* I2P-Bote: 5m77dFKGEq6~7jgtrfw56q3t~SmfwZubmGdyOLQOPoPp8MYwsZ~pfUCwud6LB1EmFxkm4C3CGlzq-hVs9WnhUV * I2P-Bote:
* 5m77dFKGEq6~7jgtrfw56q3t~SmfwZubmGdyOLQOPoPp8MYwsZ~pfUCwud6LB1EmFxkm4C3CGlzq-hVs9WnhUV
* we are the Borg. */ * we are the Borg. */
#include <errno.h> #include <errno.h>
#include <stdio.h> #include <stdio.h>
@@ -14,20 +15,20 @@
#include "../libsam3/libsam3.h" #include "../libsam3/libsam3.h"
#define KEYFILE "streams.key"
#define KEYFILE "streams.key" int main(int argc, char *argv[]) {
int main (int argc, char *argv[]) {
Sam3Session ses; Sam3Session ses;
Sam3Connection *conn; Sam3Connection *conn;
FILE *fl; FILE *fl;
// //
//libsam3_debug = 1; libsam3_debug = 1;
// //
printf("creating session...\n"); printf("creating session...\n");
// create TRANSIENT session // create TRANSIENT session
if (sam3CreateSession(&ses, SAM3_HOST_DEFAULT, SAM3_PORT_DEFAULT, SAM3_DESTINATION_TRANSIENT, SAM3_SESSION_STREAM, NULL) < 0) { if (sam3CreateSession(&ses, SAM3_HOST_DEFAULT, SAM3_PORT_DEFAULT,
SAM3_DESTINATION_TRANSIENT, SAM3_SESSION_STREAM, 4,
NULL) < 0) {
fprintf(stderr, "FATAL: can't create session\n"); fprintf(stderr, "FATAL: can't create session\n");
return 1; return 1;
} }
@@ -50,11 +51,14 @@ int main (int argc, char *argv[]) {
for (;;) { for (;;) {
char cmd[256]; char cmd[256];
// //
if (sam3tcpReceiveStr(conn->fd, cmd, sizeof(cmd)) < 0) goto error; if (sam3tcpReceiveStr(conn->fd, cmd, sizeof(cmd)) < 0)
goto error;
printf("cmd: [%s]\n", cmd); printf("cmd: [%s]\n", cmd);
if (strcmp(cmd, "quit") == 0) break; if (strcmp(cmd, "quit") == 0)
break;
// echo command // echo command
if (sam3tcpPrintf(conn->fd, "re: %s\n", cmd) < 0) goto error; if (sam3tcpPrintf(conn->fd, "re: %s\n", cmd) < 0)
goto error;
} }
// //
sam3CloseSession(&ses); sam3CloseSession(&ses);

View File

@@ -4,7 +4,8 @@
* To Public License, Version 2, as published by Sam Hocevar. See * To Public License, Version 2, as published by Sam Hocevar. See
* http://sam.zoy.org/wtfpl/COPYING for more details. * http://sam.zoy.org/wtfpl/COPYING for more details.
* *
* I2P-Bote: 5m77dFKGEq6~7jgtrfw56q3t~SmfwZubmGdyOLQOPoPp8MYwsZ~pfUCwud6LB1EmFxkm4C3CGlzq-hVs9WnhUV * I2P-Bote:
* 5m77dFKGEq6~7jgtrfw56q3t~SmfwZubmGdyOLQOPoPp8MYwsZ~pfUCwud6LB1EmFxkm4C3CGlzq-hVs9WnhUV
* we are the Borg. */ * we are the Borg. */
#include <errno.h> #include <errno.h>
#include <stdio.h> #include <stdio.h>
@@ -18,97 +19,97 @@
#include "../libsam3a/libsam3a.h" #include "../libsam3a/libsam3a.h"
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
static void scbErrorClose (Sam3ASession *ses) { static void scbErrorClose(Sam3ASession *ses) {
fprintf(stderr, "\n===============================\nSESION_ERROR: [%s]\n===============================\n", ses->error); fprintf(stderr,
"\n===============================\nSESION_ERROR: "
"[%s]\n===============================\n",
ses->error);
sam3aCloseSession(ses); // it's safe here sam3aCloseSession(ses); // it's safe here
} }
static void scbNRCreated(Sam3ASession *ses) {
static void scbNRCreated (Sam3ASession *ses) { fprintf(stderr, "\n===============================\nNAME RESOLVED: [%s]\n",
fprintf(stderr, "\n===============================\nNAME RESOLVED: [%s]\n", ses->params); ses->params);
fprintf(stderr, "PUB: %s\n===============================\n", ses->destkey); fprintf(stderr, "PUB: %s\n===============================\n", ses->destkey);
sam3aCloseSession(ses); // it's safe here sam3aCloseSession(ses); // it's safe here
} }
static const Sam3ASessionCallbacks scbNR = { static const Sam3ASessionCallbacks scbNR = {
.cbError = scbErrorClose, .cbError = scbErrorClose,
.cbCreated = scbNRCreated, .cbCreated = scbNRCreated,
.cbDisconnected = NULL, .cbDisconnected = NULL,
.cbDatagramRead = NULL, .cbDatagramRead = NULL,
.cbDestroy = NULL, .cbDestroy = NULL,
}; };
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
static void scbKGCreated (Sam3ASession *ses) { static void scbKGCreated(Sam3ASession *ses) {
fprintf(stderr, "\n===============================\nKEYS GENERATED\n"); fprintf(stderr, "\n===============================\nKEYS GENERATED\n");
fprintf(stderr, "\rPRIV: %s\n", ses->privkey); fprintf(stderr, "\rPRIV: %s\n", ses->privkey);
fprintf(stderr, "\nPUB: %s\n===============================\n", ses->pubkey); fprintf(stderr, "\nPUB: %s\n===============================\n", ses->pubkey);
sam3aCloseSession(ses); // it's safe here sam3aCloseSession(ses); // it's safe here
} }
static const Sam3ASessionCallbacks scbKG = { static const Sam3ASessionCallbacks scbKG = {
.cbError = scbErrorClose, .cbError = scbErrorClose,
.cbCreated = scbKGCreated, .cbCreated = scbKGCreated,
.cbDisconnected = NULL, .cbDisconnected = NULL,
.cbDatagramRead = NULL, .cbDatagramRead = NULL,
.cbDestroy = NULL, .cbDestroy = NULL,
}; };
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
static void scbError (Sam3ASession *ses) { static void scbError(Sam3ASession *ses) {
fprintf(stderr, "\n===============================\nSESION_ERROR: [%s]\n===============================\n", ses->error); fprintf(stderr,
"\n===============================\nSESION_ERROR: "
"[%s]\n===============================\n",
ses->error);
} }
static void scbCreated(Sam3ASession *ses) {
static void scbCreated (Sam3ASession *ses) {
fprintf(stderr, "\n===============================\nSESION_CREATED\n"); fprintf(stderr, "\n===============================\nSESION_CREATED\n");
fprintf(stderr, "\rPRIV: %s\n", ses->privkey); fprintf(stderr, "\rPRIV: %s\n", ses->privkey);
fprintf(stderr, "\nPUB: %s\n===============================\n", ses->pubkey); fprintf(stderr, "\nPUB: %s\n===============================\n", ses->pubkey);
sam3aCancelSession(ses); // it's safe here sam3aCancelSession(ses); // it's safe here
} }
static void scbDisconnected(Sam3ASession *ses) {
static void scbDisconnected (Sam3ASession *ses) { fprintf(stderr, "\n===============================\nSESION_DISCONNECTED\n===="
fprintf(stderr, "\n===============================\nSESION_DISCONNECTED\n===============================\n"); "===========================\n");
} }
static void scbDGramRead(Sam3ASession *ses, const void *buf, int bufsize) {
static void scbDGramRead (Sam3ASession *ses, const void *buf, int bufsize) { fprintf(stderr, "\n===============================\nSESION_DATAGRAM_READ\n==="
fprintf(stderr, "\n===============================\nSESION_DATAGRAM_READ\n===============================\n"); "============================\n");
} }
static void scbDestroy(Sam3ASession *ses) {
static void scbDestroy (Sam3ASession *ses) { fprintf(stderr, "\n===============================\nSESION_DESTROYED\n======="
fprintf(stderr, "\n===============================\nSESION_DESTROYED\n===============================\n"); "========================\n");
} }
/** callbacks for our SAM session */ /** callbacks for our SAM session */
static const Sam3ASessionCallbacks scb = { static const Sam3ASessionCallbacks scb = {
.cbError = scbError, .cbError = scbError,
.cbCreated = scbCreated, .cbCreated = scbCreated,
.cbDisconnected = scbDisconnected, .cbDisconnected = scbDisconnected,
.cbDatagramRead = scbDGramRead, .cbDatagramRead = scbDGramRead,
.cbDestroy = scbDestroy, .cbDestroy = scbDestroy,
}; };
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
#define HOST SAM3A_HOST_DEFAULT #define HOST SAM3A_HOST_DEFAULT
//#define HOST "google.com" //#define HOST "google.com"
int main(int argc, char *argv[]) {
int main (int argc, char *argv[]) {
Sam3ASession ses, snr, skg; Sam3ASession ses, snr, skg;
// //
//libsam3a_debug = 1; // libsam3a_debug = 1;
// //
if (sam3aCreateSession(&ses, &scb, HOST, SAM3A_PORT_DEFAULT, SAM3A_DESTINATION_TRANSIENT, SAM3A_SESSION_STREAM) < 0) { if (sam3aCreateSession(&ses, &scb, HOST, SAM3A_PORT_DEFAULT,
SAM3A_DESTINATION_TRANSIENT,
SAM3A_SESSION_STREAM) < 0) {
fprintf(stderr, "FATAL: can't create main session!\n"); fprintf(stderr, "FATAL: can't create main session!\n");
return 1; return 1;
} }
@@ -126,7 +127,8 @@ int main (int argc, char *argv[]) {
return 1; return 1;
} }
// while we have sessions ... // while we have sessions ...
while (sam3aIsActiveSession(&ses) || sam3aIsActiveSession(&snr) || sam3aIsActiveSession(&skg)) { while (sam3aIsActiveSession(&ses) || sam3aIsActiveSession(&snr) ||
sam3aIsActiveSession(&skg)) {
fd_set rds, wrs; fd_set rds, wrs;
int res, maxfd = 0; int res, maxfd = 0;
struct timeval to; struct timeval to;
@@ -134,26 +136,37 @@ int main (int argc, char *argv[]) {
FD_ZERO(&rds); FD_ZERO(&rds);
FD_ZERO(&wrs); FD_ZERO(&wrs);
// obtain the maximum fd for select() // obtain the maximum fd for select()
if (sam3aIsActiveSession(&ses) && (maxfd = sam3aAddSessionToFDS(&ses, -1, &rds, &wrs)) < 0) break; if (sam3aIsActiveSession(&ses) &&
if (sam3aIsActiveSession(&snr) && (maxfd = sam3aAddSessionToFDS(&snr, -1, &rds, &wrs)) < 0) break; (maxfd = sam3aAddSessionToFDS(&ses, -1, &rds, &wrs)) < 0)
if (sam3aIsActiveSession(&skg) && (maxfd = sam3aAddSessionToFDS(&skg, -1, &rds, &wrs)) < 0) break; break;
if (sam3aIsActiveSession(&snr) &&
(maxfd = sam3aAddSessionToFDS(&snr, -1, &rds, &wrs)) < 0)
break;
if (sam3aIsActiveSession(&skg) &&
(maxfd = sam3aAddSessionToFDS(&skg, -1, &rds, &wrs)) < 0)
break;
// set timeout to 1 second // set timeout to 1 second
sam3ams2timeval(&to, 1000); sam3ams2timeval(&to, 1000);
// call select() // call select()
res = select(maxfd+1, &rds, &wrs, NULL, &to); res = select(maxfd + 1, &rds, &wrs, NULL, &to);
if (res < 0) { if (res < 0) {
if (errno == EINTR) continue; if (errno == EINTR)
continue;
fprintf(stderr, "FATAL: select() error!\n"); fprintf(stderr, "FATAL: select() error!\n");
break; break;
} }
if (res == 0) { if (res == 0) {
// idle, no activity // idle, no activity
fprintf(stdout, "."); fflush(stdout); fprintf(stdout, ".");
fflush(stdout);
} else { } else {
// we have activity, process io // we have activity, process io
if (sam3aIsActiveSession(&ses)) sam3aProcessSessionIO(&ses, &rds, &wrs); if (sam3aIsActiveSession(&ses))
if (sam3aIsActiveSession(&snr)) sam3aProcessSessionIO(&snr, &rds, &wrs); sam3aProcessSessionIO(&ses, &rds, &wrs);
if (sam3aIsActiveSession(&skg)) sam3aProcessSessionIO(&skg, &rds, &wrs); if (sam3aIsActiveSession(&snr))
sam3aProcessSessionIO(&snr, &rds, &wrs);
if (sam3aIsActiveSession(&skg))
sam3aProcessSessionIO(&skg, &rds, &wrs);
} }
} }
// close seessions // close seessions

View File

@@ -4,7 +4,8 @@
* To Public License, Version 2, as published by Sam Hocevar. See * To Public License, Version 2, as published by Sam Hocevar. See
* http://sam.zoy.org/wtfpl/COPYING for more details. * http://sam.zoy.org/wtfpl/COPYING for more details.
* *
* I2P-Bote: 5m77dFKGEq6~7jgtrfw56q3t~SmfwZubmGdyOLQOPoPp8MYwsZ~pfUCwud6LB1EmFxkm4C3CGlzq-hVs9WnhUV * I2P-Bote:
* 5m77dFKGEq6~7jgtrfw56q3t~SmfwZubmGdyOLQOPoPp8MYwsZ~pfUCwud6LB1EmFxkm4C3CGlzq-hVs9WnhUV
* we are the Borg. */ * we are the Borg. */
#include <errno.h> #include <errno.h>
#include <stdio.h> #include <stdio.h>
@@ -18,86 +19,90 @@
#include "../libsam3a/libsam3a.h" #include "../libsam3a/libsam3a.h"
////////////////////////////////////////////////////////////////////////////////
#define KEYFILE "streams.key"
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
#define KEYFILE "streams.key" static void ccbError(Sam3AConnection *ct) {
fprintf(stderr,
"\n===============================\nCONNECTION_ERROR: "
//////////////////////////////////////////////////////////////////////////////// "[%s]\n===============================\n",
static void ccbError (Sam3AConnection *ct) { ct->error);
fprintf(stderr, "\n===============================\nCONNECTION_ERROR: [%s]\n===============================\n", ct->error);
} }
static void ccbDisconnected(Sam3AConnection *ct) {
static void ccbDisconnected (Sam3AConnection *ct) { fprintf(stderr, "\n===============================\nCONNECTION_"
fprintf(stderr, "\n===============================\nCONNECTION_DISCONNECTED\n===============================\n"); "DISCONNECTED\n===============================\n");
} }
static void ccbConnected(Sam3AConnection *ct) {
static void ccbConnected (Sam3AConnection *ct) { fprintf(stderr, "\n===============================\nCONNECTION_CONNECTED\n==="
fprintf(stderr, "\n===============================\nCONNECTION_CONNECTED\n===============================\n"); "============================\n");
//sam3aCancelConnection(ct); // cbSent() will not be called // sam3aCancelConnection(ct); // cbSent() will not be called
} }
static void ccbAccepted(Sam3AConnection *ct) {
static void ccbAccepted (Sam3AConnection *ct) { fprintf(stderr, "\n===============================\nCONNECTION_ACCEPTED\n===="
fprintf(stderr, "\n===============================\nCONNECTION_ACCEPTED\n===============================\n"); "===========================\n");
} }
static void ccbSent(Sam3AConnection *ct) {
static void ccbSent (Sam3AConnection *ct) { fprintf(stderr, "\n===============================\nCONNECTION_WANTBYTES\n==="
fprintf(stderr, "\n===============================\nCONNECTION_WANTBYTES\n===============================\n"); "============================\n");
//sam3aCancelConnection(ct); // sam3aCancelConnection(ct);
//sam3aCancelSession(ct->ses); // hehe // sam3aCancelSession(ct->ses); // hehe
fprintf(stderr, "(%p)\n", ct->udata); fprintf(stderr, "(%p)\n", ct->udata);
// //
switch ((intptr_t)ct->udata) { switch ((intptr_t)ct->udata) {
case 0: case 0:
if (sam3aSend(ct, "test\n", -1) < 0) { if (sam3aSend(ct, "test\n", -1) < 0) {
fprintf(stderr, "SEND ERROR!\n"); fprintf(stderr, "SEND ERROR!\n");
sam3aCancelSession(ct->ses); // hehe sam3aCancelSession(ct->ses); // hehe
} }
break; break;
case 1: case 1:
if (sam3aSend(ct, "quit\n", -1) < 0) { if (sam3aSend(ct, "quit\n", -1) < 0) {
fprintf(stderr, "SEND ERROR!\n"); fprintf(stderr, "SEND ERROR!\n");
sam3aCancelSession(ct->ses); // hehe sam3aCancelSession(ct->ses); // hehe
} }
break; break;
default: return; default:
return;
} }
ct->udata = (void *)(((intptr_t)ct->udata)+1); ct->udata = (void *)(((intptr_t)ct->udata) + 1);
} }
static void ccbRead(Sam3AConnection *ct, const void *buf, int bufsize) {
static void ccbRead (Sam3AConnection *ct, const void *buf, int bufsize) { fprintf(stderr,
fprintf(stderr, "\n===============================\nCONNECTION_GOTBYTES (%d)\n===============================\n", bufsize); "\n===============================\nCONNECTION_GOTBYTES "
"(%d)\n===============================\n",
bufsize);
} }
static void ccbDestroy(Sam3AConnection *ct) {
static void ccbDestroy (Sam3AConnection *ct) { fprintf(stderr, "\n===============================\nCONNECTION_DESTROY\n====="
fprintf(stderr, "\n===============================\nCONNECTION_DESTROY\n===============================\n"); "==========================\n");
} }
static const Sam3AConnectionCallbacks ccb = { static const Sam3AConnectionCallbacks ccb = {
.cbError = ccbError, .cbError = ccbError,
.cbDisconnected = ccbDisconnected, .cbDisconnected = ccbDisconnected,
.cbConnected = ccbConnected, .cbConnected = ccbConnected,
.cbAccepted = ccbAccepted, .cbAccepted = ccbAccepted,
.cbSent = ccbSent, .cbSent = ccbSent,
.cbRead = ccbRead, .cbRead = ccbRead,
.cbDestroy = ccbDestroy, .cbDestroy = ccbDestroy,
}; };
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
static void scbError (Sam3ASession *ses) { static void scbError(Sam3ASession *ses) {
fprintf(stderr, "\n===============================\nSESION_ERROR: [%s]\n===============================\n", ses->error); fprintf(stderr,
"\n===============================\nSESION_ERROR: "
"[%s]\n===============================\n",
ses->error);
} }
static void scbCreated(Sam3ASession *ses) {
static void scbCreated (Sam3ASession *ses) {
char destkey[517]; char destkey[517];
FILE *fl; FILE *fl;
// //
@@ -128,42 +133,41 @@ static void scbCreated (Sam3ASession *ses) {
fprintf(stderr, "GOON: creating connection...\n"); fprintf(stderr, "GOON: creating connection...\n");
} }
static void scbDisconnected(Sam3ASession *ses) {
static void scbDisconnected (Sam3ASession *ses) { fprintf(stderr, "\n===============================\nSESION_DISCONNECTED\n===="
fprintf(stderr, "\n===============================\nSESION_DISCONNECTED\n===============================\n"); "===========================\n");
} }
static void scbDGramRead(Sam3ASession *ses, const void *buf, int bufsize) {
static void scbDGramRead (Sam3ASession *ses, const void *buf, int bufsize) { fprintf(stderr, "\n===============================\nSESION_DATAGRAM_READ\n==="
fprintf(stderr, "\n===============================\nSESION_DATAGRAM_READ\n===============================\n"); "============================\n");
} }
static void scbDestroy(Sam3ASession *ses) {
static void scbDestroy (Sam3ASession *ses) { fprintf(stderr, "\n===============================\nSESION_DESTROYED\n======="
fprintf(stderr, "\n===============================\nSESION_DESTROYED\n===============================\n"); "========================\n");
} }
static const Sam3ASessionCallbacks scb = { static const Sam3ASessionCallbacks scb = {
.cbError = scbError, .cbError = scbError,
.cbCreated = scbCreated, .cbCreated = scbCreated,
.cbDisconnected = scbDisconnected, .cbDisconnected = scbDisconnected,
.cbDatagramRead = scbDGramRead, .cbDatagramRead = scbDGramRead,
.cbDestroy = scbDestroy, .cbDestroy = scbDestroy,
}; };
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
#define HOST SAM3A_HOST_DEFAULT #define HOST SAM3A_HOST_DEFAULT
//#define HOST "google.com" //#define HOST "google.com"
int main(int argc, char *argv[]) {
int main (int argc, char *argv[]) {
Sam3ASession ses; Sam3ASession ses;
// //
libsam3a_debug = 0; libsam3a_debug = 0;
// //
if (sam3aCreateSession(&ses, &scb, HOST, SAM3A_PORT_DEFAULT, SAM3A_DESTINATION_TRANSIENT, SAM3A_SESSION_STREAM) < 0) { if (sam3aCreateSession(&ses, &scb, HOST, SAM3A_PORT_DEFAULT,
SAM3A_DESTINATION_TRANSIENT,
SAM3A_SESSION_STREAM) < 0) {
fprintf(stderr, "FATAL: can't create main session!\n"); fprintf(stderr, "FATAL: can't create main session!\n");
return 1; return 1;
} }
@@ -175,18 +179,23 @@ int main (int argc, char *argv[]) {
// //
FD_ZERO(&rds); FD_ZERO(&rds);
FD_ZERO(&wrs); FD_ZERO(&wrs);
if (sam3aIsActiveSession(&ses) && (maxfd = sam3aAddSessionToFDS(&ses, -1, &rds, &wrs)) < 0) break; if (sam3aIsActiveSession(&ses) &&
(maxfd = sam3aAddSessionToFDS(&ses, -1, &rds, &wrs)) < 0)
break;
sam3ams2timeval(&to, 1000); sam3ams2timeval(&to, 1000);
res = select(maxfd+1, &rds, &wrs, NULL, &to); res = select(maxfd + 1, &rds, &wrs, NULL, &to);
if (res < 0) { if (res < 0) {
if (errno == EINTR) continue; if (errno == EINTR)
continue;
fprintf(stderr, "FATAL: select() error!\n"); fprintf(stderr, "FATAL: select() error!\n");
break; break;
} }
if (res == 0) { if (res == 0) {
fprintf(stdout, "."); fflush(stdout); fprintf(stdout, ".");
fflush(stdout);
} else { } else {
if (sam3aIsActiveSession(&ses)) sam3aProcessSessionIO(&ses, &rds, &wrs); if (sam3aIsActiveSession(&ses))
sam3aProcessSessionIO(&ses, &rds, &wrs);
} }
} }
// //

View File

@@ -4,7 +4,8 @@
* To Public License, Version 2, as published by Sam Hocevar. See * To Public License, Version 2, as published by Sam Hocevar. See
* http://sam.zoy.org/wtfpl/COPYING for more details. * http://sam.zoy.org/wtfpl/COPYING for more details.
* *
* I2P-Bote: 5m77dFKGEq6~7jgtrfw56q3t~SmfwZubmGdyOLQOPoPp8MYwsZ~pfUCwud6LB1EmFxkm4C3CGlzq-hVs9WnhUV * I2P-Bote:
* 5m77dFKGEq6~7jgtrfw56q3t~SmfwZubmGdyOLQOPoPp8MYwsZ~pfUCwud6LB1EmFxkm4C3CGlzq-hVs9WnhUV
* we are the Borg. */ * we are the Borg. */
#include <errno.h> #include <errno.h>
#include <stdio.h> #include <stdio.h>
@@ -18,10 +19,8 @@
#include "../libsam3a/libsam3a.h" #include "../libsam3a/libsam3a.h"
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
#define KEYFILE "streams.key" #define KEYFILE "streams.key"
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
typedef struct { typedef struct {
@@ -31,63 +30,67 @@ typedef struct {
int doQuit; int doQuit;
} ConnData; } ConnData;
static void cdAppendChar(ConnData *d, char ch) {
static void cdAppendChar (ConnData *d, char ch) { if (d->strused + 1 >= d->strsize) {
if (d->strused+1 >= d->strsize) {
// fuck errors // fuck errors
d->strsize = d->strused+1024; d->strsize = d->strused + 1024;
d->str = realloc(d->str, d->strsize+1); d->str = realloc(d->str, d->strsize + 1);
} }
d->str[d->strused++] = ch; d->str[d->strused++] = ch;
d->str[d->strused] = 0; d->str[d->strused] = 0;
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
static void ccbError (Sam3AConnection *ct) { static void ccbError(Sam3AConnection *ct) {
fprintf(stderr, "\n===============================\nCONNECTION_ERROR: [%s]\n===============================\n", ct->error); fprintf(stderr,
"\n===============================\nCONNECTION_ERROR: "
"[%s]\n===============================\n",
ct->error);
} }
static void ccbDisconnected(Sam3AConnection *ct) {
static void ccbDisconnected (Sam3AConnection *ct) { fprintf(stderr, "\n===============================\nCONNECTION_"
fprintf(stderr, "\n===============================\nCONNECTION_DISCONNECTED\n===============================\n"); "DISCONNECTED\n===============================\n");
} }
static void ccbConnected(Sam3AConnection *ct) {
static void ccbConnected (Sam3AConnection *ct) { fprintf(stderr, "\n===============================\nCONNECTION_CONNECTED\n==="
fprintf(stderr, "\n===============================\nCONNECTION_CONNECTED\n===============================\n"); "============================\n");
//sam3aCancelConnection(ct); // cbSent() will not be called // sam3aCancelConnection(ct); // cbSent() will not be called
} }
static void ccbAccepted(Sam3AConnection *ct) {
static void ccbAccepted (Sam3AConnection *ct) { fprintf(stderr, "\n===============================\nCONNECTION_ACCEPTED\n===="
fprintf(stderr, "\n===============================\nCONNECTION_ACCEPTED\n===============================\n"); "===========================\n");
fprintf(stderr, "FROM: %s\n===============================\n", ct->destkey); fprintf(stderr, "FROM: %s\n===============================\n", ct->destkey);
} }
static void ccbSent(Sam3AConnection *ct) {
static void ccbSent (Sam3AConnection *ct) {
ConnData *d = (ConnData *)ct->udata; ConnData *d = (ConnData *)ct->udata;
// //
fprintf(stderr, "\n===============================\nCONNECTION_WANTBYTES\n===============================\n"); fprintf(stderr, "\n===============================\nCONNECTION_WANTBYTES\n==="
"============================\n");
if (d->doQuit) { if (d->doQuit) {
sam3aCancelSession(ct->ses); // hehe sam3aCancelSession(ct->ses); // hehe
} }
} }
static void ccbRead(Sam3AConnection *ct, const void *buf, int bufsize) {
static void ccbRead (Sam3AConnection *ct, const void *buf, int bufsize) {
const char *b = (const char *)buf; const char *b = (const char *)buf;
ConnData *d = (ConnData *)ct->udata; ConnData *d = (ConnData *)ct->udata;
// //
fprintf(stderr, "\n===============================\nCONNECTION_GOTBYTES (%d)\n===============================\n", bufsize); fprintf(stderr,
"\n===============================\nCONNECTION_GOTBYTES "
"(%d)\n===============================\n",
bufsize);
while (bufsize > 0) { while (bufsize > 0) {
cdAppendChar(ct->udata, *b); cdAppendChar(ct->udata, *b);
if (*b == '\n') { if (*b == '\n') {
fprintf(stderr, "cmd: %s", d->str); fprintf(stderr, "cmd: %s", d->str);
if (strcasecmp(d->str, "quit\n") == 0) d->doQuit = 1; if (strcasecmp(d->str, "quit\n") == 0)
d->doQuit = 1;
if (sam3aSend(ct, d->str, -1) < 0) { if (sam3aSend(ct, d->str, -1) < 0) {
//sam3aCancelConnection(ct); // hehe // sam3aCancelConnection(ct); // hehe
sam3aCancelSession(ct->ses); // hehe sam3aCancelSession(ct->ses); // hehe
return; return;
} }
@@ -99,36 +102,37 @@ static void ccbRead (Sam3AConnection *ct, const void *buf, int bufsize) {
} }
} }
static void ccbDestroy(Sam3AConnection *ct) {
static void ccbDestroy (Sam3AConnection *ct) { fprintf(stderr, "\n===============================\nCONNECTION_DESTROY\n====="
fprintf(stderr, "\n===============================\nCONNECTION_DESTROY\n===============================\n"); "==========================\n");
if (ct->udata != NULL) { if (ct->udata != NULL) {
ConnData *d = (ConnData *)ct->udata; ConnData *d = (ConnData *)ct->udata;
// //
if (d->str != NULL) free(d->str); if (d->str != NULL)
free(d->str);
free(d); free(d);
} }
} }
static const Sam3AConnectionCallbacks ccb = { static const Sam3AConnectionCallbacks ccb = {
.cbError = ccbError, .cbError = ccbError,
.cbDisconnected = ccbDisconnected, .cbDisconnected = ccbDisconnected,
.cbConnected = ccbConnected, .cbConnected = ccbConnected,
.cbAccepted = ccbAccepted, .cbAccepted = ccbAccepted,
.cbSent = ccbSent, .cbSent = ccbSent,
.cbRead = ccbRead, .cbRead = ccbRead,
.cbDestroy = ccbDestroy, .cbDestroy = ccbDestroy,
}; };
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
static void scbError (Sam3ASession *ses) { static void scbError(Sam3ASession *ses) {
fprintf(stderr, "\n===============================\nSESION_ERROR: [%s]\n===============================\n", ses->error); fprintf(stderr,
"\n===============================\nSESION_ERROR: "
"[%s]\n===============================\n",
ses->error);
} }
static void scbCreated(Sam3ASession *ses) {
static void scbCreated (Sam3ASession *ses) {
FILE *fl; FILE *fl;
Sam3AConnection *conn; Sam3AConnection *conn;
// //
@@ -160,42 +164,41 @@ static void scbCreated (Sam3ASession *ses) {
fprintf(stderr, "GOON: accepting connection...\n"); fprintf(stderr, "GOON: accepting connection...\n");
} }
static void scbDisconnected(Sam3ASession *ses) {
static void scbDisconnected (Sam3ASession *ses) { fprintf(stderr, "\n===============================\nSESION_DISCONNECTED\n===="
fprintf(stderr, "\n===============================\nSESION_DISCONNECTED\n===============================\n"); "===========================\n");
} }
static void scbDGramRead(Sam3ASession *ses, const void *buf, int bufsize) {
static void scbDGramRead (Sam3ASession *ses, const void *buf, int bufsize) { fprintf(stderr, "\n===============================\nSESION_DATAGRAM_READ\n==="
fprintf(stderr, "\n===============================\nSESION_DATAGRAM_READ\n===============================\n"); "============================\n");
} }
static void scbDestroy(Sam3ASession *ses) {
static void scbDestroy (Sam3ASession *ses) { fprintf(stderr, "\n===============================\nSESION_DESTROYED\n======="
fprintf(stderr, "\n===============================\nSESION_DESTROYED\n===============================\n"); "========================\n");
} }
static const Sam3ASessionCallbacks scb = { static const Sam3ASessionCallbacks scb = {
.cbError = scbError, .cbError = scbError,
.cbCreated = scbCreated, .cbCreated = scbCreated,
.cbDisconnected = scbDisconnected, .cbDisconnected = scbDisconnected,
.cbDatagramRead = scbDGramRead, .cbDatagramRead = scbDGramRead,
.cbDestroy = scbDestroy, .cbDestroy = scbDestroy,
}; };
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
#define HOST SAM3A_HOST_DEFAULT #define HOST SAM3A_HOST_DEFAULT
//#define HOST "google.com" //#define HOST "google.com"
int main(int argc, char *argv[]) {
int main (int argc, char *argv[]) {
Sam3ASession ses; Sam3ASession ses;
// //
libsam3a_debug = 0; libsam3a_debug = 0;
// //
if (sam3aCreateSession(&ses, &scb, HOST, SAM3A_PORT_DEFAULT, SAM3A_DESTINATION_TRANSIENT, SAM3A_SESSION_STREAM) < 0) { if (sam3aCreateSession(&ses, &scb, HOST, SAM3A_PORT_DEFAULT,
SAM3A_DESTINATION_TRANSIENT,
SAM3A_SESSION_STREAM) < 0) {
fprintf(stderr, "FATAL: can't create main session!\n"); fprintf(stderr, "FATAL: can't create main session!\n");
return 1; return 1;
} }
@@ -207,18 +210,23 @@ int main (int argc, char *argv[]) {
// //
FD_ZERO(&rds); FD_ZERO(&rds);
FD_ZERO(&wrs); FD_ZERO(&wrs);
if (sam3aIsActiveSession(&ses) && (maxfd = sam3aAddSessionToFDS(&ses, -1, &rds, &wrs)) < 0) break; if (sam3aIsActiveSession(&ses) &&
(maxfd = sam3aAddSessionToFDS(&ses, -1, &rds, &wrs)) < 0)
break;
sam3ams2timeval(&to, 1000); sam3ams2timeval(&to, 1000);
res = select(maxfd+1, &rds, &wrs, NULL, &to); res = select(maxfd + 1, &rds, &wrs, NULL, &to);
if (res < 0) { if (res < 0) {
if (errno == EINTR) continue; if (errno == EINTR)
continue;
fprintf(stderr, "FATAL: select() error!\n"); fprintf(stderr, "FATAL: select() error!\n");
break; break;
} }
if (res == 0) { if (res == 0) {
fprintf(stdout, "."); fflush(stdout); fprintf(stdout, ".");
fflush(stdout);
} else { } else {
if (sam3aIsActiveSession(&ses)) sam3aProcessSessionIO(&ses, &rds, &wrs); if (sam3aIsActiveSession(&ses))
sam3aProcessSessionIO(&ses, &rds, &wrs);
} }
} }
// //

View File

@@ -26,10 +26,10 @@
#include "tinytest_local.h" #include "tinytest_local.h"
#endif #endif
#include <assert.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <assert.h>
#ifndef NO_FORKING #ifndef NO_FORKING
@@ -42,8 +42,8 @@
#endif #endif
#if defined(__APPLE__) && defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) #if defined(__APPLE__) && defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__)
#if (__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 1060 && \ #if (__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 1060 && \
__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 1070) __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 1070)
/* Workaround for a stupid bug in OSX 10.6 */ /* Workaround for a stupid bug in OSX 10.6 */
#define FORK_BREAKS_GCOV #define FORK_BREAKS_GCOV
#include <vproc.h> #include <vproc.h>
@@ -62,18 +62,18 @@
#define LONGEST_TEST_NAME 16384 #define LONGEST_TEST_NAME 16384
static int in_tinytest_main = 0; /**< true if we're in tinytest_main().*/ static int in_tinytest_main = 0; /**< true if we're in tinytest_main().*/
static int n_ok = 0; /**< Number of tests that have passed */ static int n_ok = 0; /**< Number of tests that have passed */
static int n_bad = 0; /**< Number of tests that have failed. */ static int n_bad = 0; /**< Number of tests that have failed. */
static int n_skipped = 0; /**< Number of tests that have been skipped. */ static int n_skipped = 0; /**< Number of tests that have been skipped. */
static int opt_forked = 0; /**< True iff we're called from inside a win32 fork*/ static int opt_forked = 0; /**< True iff we're called from inside a win32 fork*/
static int opt_nofork = 0; /**< Suppress calls to fork() for debugging. */ static int opt_nofork = 0; /**< Suppress calls to fork() for debugging. */
static int opt_verbosity = 1; /**< -==quiet,0==terse,1==normal,2==verbose */ static int opt_verbosity = 1; /**< -==quiet,0==terse,1==normal,2==verbose */
const char *verbosity_flag = ""; const char *verbosity_flag = "";
const struct testlist_alias_t *cfg_aliases=NULL; const struct testlist_alias_t *cfg_aliases = NULL;
enum outcome { SKIP=2, OK=1, FAIL=0 }; enum outcome { SKIP = 2, OK = 1, FAIL = 0 };
static enum outcome cur_test_outcome = FAIL; static enum outcome cur_test_outcome = FAIL;
const char *cur_test_prefix = NULL; /**< prefix of the current test group */ const char *cur_test_prefix = NULL; /**< prefix of the current test group */
/** Name of the current test, if we haven't logged is yet. Used for --quiet */ /** Name of the current test, if we haven't logged is yet. Used for --quiet */
@@ -81,413 +81,386 @@ const char *cur_test_name = NULL;
#ifdef _WIN32 #ifdef _WIN32
/* Copy of argv[0] for win32. */ /* Copy of argv[0] for win32. */
static char commandname[MAX_PATH+1]; static char commandname[MAX_PATH + 1];
#endif #endif
static void usage(struct testgroup_t *groups, int list_groups) static void usage(struct testgroup_t *groups, int list_groups)
__attribute__((noreturn)); __attribute__((noreturn));
static int process_test_option(struct testgroup_t *groups, const char *test); static int process_test_option(struct testgroup_t *groups, const char *test);
static enum outcome static enum outcome testcase_run_bare_(const struct testcase_t *testcase) {
testcase_run_bare_(const struct testcase_t *testcase) void *env = NULL;
{ enum outcome outcome;
void *env = NULL; if (testcase->setup) {
enum outcome outcome; env = testcase->setup->setup_fn(testcase);
if (testcase->setup) { if (!env)
env = testcase->setup->setup_fn(testcase); return FAIL;
if (!env) else if (env == (void *)TT_SKIP)
return FAIL; return SKIP;
else if (env == (void*)TT_SKIP) }
return SKIP;
}
cur_test_outcome = OK; cur_test_outcome = OK;
testcase->fn(env); testcase->fn(env);
outcome = cur_test_outcome; outcome = cur_test_outcome;
if (testcase->setup) { if (testcase->setup) {
if (testcase->setup->cleanup_fn(testcase, env) == 0) if (testcase->setup->cleanup_fn(testcase, env) == 0)
outcome = FAIL; outcome = FAIL;
} }
return outcome; return outcome;
} }
#define MAGIC_EXITCODE 42 #define MAGIC_EXITCODE 42
#ifndef NO_FORKING #ifndef NO_FORKING
static enum outcome static enum outcome testcase_run_forked_(const struct testgroup_t *group,
testcase_run_forked_(const struct testgroup_t *group, const struct testcase_t *testcase) {
const struct testcase_t *testcase)
{
#ifdef _WIN32 #ifdef _WIN32
/* Fork? On Win32? How primitive! We'll do what the smart kids do: /* Fork? On Win32? How primitive! We'll do what the smart kids do:
we'll invoke our own exe (whose name we recall from the command we'll invoke our own exe (whose name we recall from the command
line) with a command line that tells it to run just the test we line) with a command line that tells it to run just the test we
want, and this time without forking. want, and this time without forking.
(No, threads aren't an option. The whole point of forking is to (No, threads aren't an option. The whole point of forking is to
share no state between tests.) share no state between tests.)
*/ */
int ok; int ok;
char buffer[LONGEST_TEST_NAME+256]; char buffer[LONGEST_TEST_NAME + 256];
STARTUPINFOA si; STARTUPINFOA si;
PROCESS_INFORMATION info; PROCESS_INFORMATION info;
DWORD exitcode; DWORD exitcode;
if (!in_tinytest_main) { if (!in_tinytest_main) {
printf("\nERROR. On Windows, testcase_run_forked_ must be" printf("\nERROR. On Windows, testcase_run_forked_ must be"
" called from within tinytest_main.\n"); " called from within tinytest_main.\n");
abort(); abort();
} }
if (opt_verbosity>0) if (opt_verbosity > 0)
printf("[forking] "); printf("[forking] ");
snprintf(buffer, sizeof(buffer), "%s --RUNNING-FORKED %s %s%s", snprintf(buffer, sizeof(buffer), "%s --RUNNING-FORKED %s %s%s", commandname,
commandname, verbosity_flag, group->prefix, testcase->name); verbosity_flag, group->prefix, testcase->name);
memset(&si, 0, sizeof(si)); memset(&si, 0, sizeof(si));
memset(&info, 0, sizeof(info)); memset(&info, 0, sizeof(info));
si.cb = sizeof(si); si.cb = sizeof(si);
ok = CreateProcessA(commandname, buffer, NULL, NULL, 0, ok = CreateProcessA(commandname, buffer, NULL, NULL, 0, 0, NULL, NULL, &si,
0, NULL, NULL, &si, &info); &info);
if (!ok) { if (!ok) {
printf("CreateProcess failed!\n"); printf("CreateProcess failed!\n");
return 0; return 0;
} }
WaitForSingleObject(info.hProcess, INFINITE); WaitForSingleObject(info.hProcess, INFINITE);
GetExitCodeProcess(info.hProcess, &exitcode); GetExitCodeProcess(info.hProcess, &exitcode);
CloseHandle(info.hProcess); CloseHandle(info.hProcess);
CloseHandle(info.hThread); CloseHandle(info.hThread);
if (exitcode == 0) if (exitcode == 0)
return OK; return OK;
else if (exitcode == MAGIC_EXITCODE) else if (exitcode == MAGIC_EXITCODE)
return SKIP; return SKIP;
else else
return FAIL; return FAIL;
#else #else
int outcome_pipe[2]; int outcome_pipe[2];
pid_t pid; pid_t pid;
(void)group; (void)group;
if (pipe(outcome_pipe)) if (pipe(outcome_pipe))
perror("opening pipe"); perror("opening pipe");
if (opt_verbosity>0) if (opt_verbosity > 0)
printf("[forking] "); printf("[forking] ");
pid = fork(); pid = fork();
#ifdef FORK_BREAKS_GCOV #ifdef FORK_BREAKS_GCOV
vproc_transaction_begin(0); vproc_transaction_begin(0);
#endif #endif
if (!pid) { if (!pid) {
/* child. */ /* child. */
int test_r, write_r; int test_r, write_r;
char b[1]; char b[1];
close(outcome_pipe[0]); close(outcome_pipe[0]);
test_r = testcase_run_bare_(testcase); test_r = testcase_run_bare_(testcase);
assert(0<=(int)test_r && (int)test_r<=2); assert(0 <= (int)test_r && (int)test_r <= 2);
b[0] = "NYS"[test_r]; b[0] = "NYS"[test_r];
write_r = (int)write(outcome_pipe[1], b, 1); write_r = (int)write(outcome_pipe[1], b, 1);
if (write_r != 1) { if (write_r != 1) {
perror("write outcome to pipe"); perror("write outcome to pipe");
exit(1); exit(1);
} }
exit(0); exit(0);
return FAIL; /* unreachable */ return FAIL; /* unreachable */
} else { } else {
/* parent */ /* parent */
int status, r; int status, r;
char b[1]; char b[1];
/* Close this now, so that if the other side closes it, /* Close this now, so that if the other side closes it,
* our read fails. */ * our read fails. */
close(outcome_pipe[1]); close(outcome_pipe[1]);
r = (int)read(outcome_pipe[0], b, 1); r = (int)read(outcome_pipe[0], b, 1);
if (r == 0) { if (r == 0) {
printf("[Lost connection!] "); printf("[Lost connection!] ");
return FAIL; return FAIL;
} else if (r != 1) { } else if (r != 1) {
perror("read outcome from pipe"); perror("read outcome from pipe");
} }
waitpid(pid, &status, 0); waitpid(pid, &status, 0);
close(outcome_pipe[0]); close(outcome_pipe[0]);
return b[0]=='Y' ? OK : (b[0]=='S' ? SKIP : FAIL); return b[0] == 'Y' ? OK : (b[0] == 'S' ? SKIP : FAIL);
} }
#endif #endif
} }
#endif /* !NO_FORKING */ #endif /* !NO_FORKING */
int int testcase_run_one(const struct testgroup_t *group,
testcase_run_one(const struct testgroup_t *group, const struct testcase_t *testcase) {
const struct testcase_t *testcase) enum outcome outcome;
{
enum outcome outcome;
if (testcase->flags & (TT_SKIP|TT_OFF_BY_DEFAULT)) { if (testcase->flags & (TT_SKIP | TT_OFF_BY_DEFAULT)) {
if (opt_verbosity>0) if (opt_verbosity > 0)
printf("%s%s: %s\n", printf("%s%s: %s\n", group->prefix, testcase->name,
group->prefix, testcase->name, (testcase->flags & TT_SKIP) ? "SKIPPED" : "DISABLED");
(testcase->flags & TT_SKIP) ? "SKIPPED" : "DISABLED"); ++n_skipped;
++n_skipped; return SKIP;
return SKIP; }
}
if (opt_verbosity>0 && !opt_forked) { if (opt_verbosity > 0 && !opt_forked) {
printf("%s%s: ", group->prefix, testcase->name); printf("%s%s: ", group->prefix, testcase->name);
} else { } else {
if (opt_verbosity==0) printf("."); if (opt_verbosity == 0)
cur_test_prefix = group->prefix; printf(".");
cur_test_name = testcase->name; cur_test_prefix = group->prefix;
} cur_test_name = testcase->name;
}
#ifndef NO_FORKING #ifndef NO_FORKING
if ((testcase->flags & TT_FORK) && !(opt_forked||opt_nofork)) { if ((testcase->flags & TT_FORK) && !(opt_forked || opt_nofork)) {
outcome = testcase_run_forked_(group, testcase); outcome = testcase_run_forked_(group, testcase);
} else { } else {
#else #else
{ {
#endif #endif
outcome = testcase_run_bare_(testcase); outcome = testcase_run_bare_(testcase);
} }
if (outcome == OK) { if (outcome == OK) {
++n_ok; ++n_ok;
if (opt_verbosity>0 && !opt_forked) if (opt_verbosity > 0 && !opt_forked)
puts(opt_verbosity==1?"OK":""); puts(opt_verbosity == 1 ? "OK" : "");
} else if (outcome == SKIP) { } else if (outcome == SKIP) {
++n_skipped; ++n_skipped;
if (opt_verbosity>0 && !opt_forked) if (opt_verbosity > 0 && !opt_forked)
puts("SKIPPED"); puts("SKIPPED");
} else { } else {
++n_bad; ++n_bad;
if (!opt_forked) if (!opt_forked)
printf("\n [%s FAILED]\n", testcase->name); printf("\n [%s FAILED]\n", testcase->name);
} }
if (opt_forked) { if (opt_forked) {
exit(outcome==OK ? 0 : (outcome==SKIP?MAGIC_EXITCODE : 1)); exit(outcome == OK ? 0 : (outcome == SKIP ? MAGIC_EXITCODE : 1));
return 1; /* unreachable */ return 1; /* unreachable */
} else { } else {
return (int)outcome; return (int)outcome;
} }
} }
int int tinytest_set_flag_(struct testgroup_t *groups, const char *arg, int set,
tinytest_set_flag_(struct testgroup_t *groups, const char *arg, int set, unsigned long flag) unsigned long flag) {
{ int i, j;
int i, j; size_t length = LONGEST_TEST_NAME;
size_t length = LONGEST_TEST_NAME; char fullname[LONGEST_TEST_NAME];
char fullname[LONGEST_TEST_NAME]; int found = 0;
int found=0; if (strstr(arg, ".."))
if (strstr(arg, "..")) length = strstr(arg, "..") - arg;
length = strstr(arg,"..")-arg; for (i = 0; groups[i].prefix; ++i) {
for (i=0; groups[i].prefix; ++i) { for (j = 0; groups[i].cases[j].name; ++j) {
for (j=0; groups[i].cases[j].name; ++j) { struct testcase_t *testcase = &groups[i].cases[j];
struct testcase_t *testcase = &groups[i].cases[j]; snprintf(fullname, sizeof(fullname), "%s%s", groups[i].prefix,
snprintf(fullname, sizeof(fullname), "%s%s", testcase->name);
groups[i].prefix, testcase->name); if (!flag) { /* Hack! */
if (!flag) { /* Hack! */ printf(" %s", fullname);
printf(" %s", fullname); if (testcase->flags & TT_OFF_BY_DEFAULT)
if (testcase->flags & TT_OFF_BY_DEFAULT) puts(" (Off by default)");
puts(" (Off by default)"); else if (testcase->flags & TT_SKIP)
else if (testcase->flags & TT_SKIP) puts(" (DISABLED)");
puts(" (DISABLED)"); else
else puts("");
puts(""); }
} if (!strncmp(fullname, arg, length)) {
if (!strncmp(fullname, arg, length)) { if (set)
if (set) testcase->flags |= flag;
testcase->flags |= flag; else
else testcase->flags &= ~flag;
testcase->flags &= ~flag; ++found;
++found; }
} }
} }
} return found;
return found;
} }
static void static void usage(struct testgroup_t *groups, int list_groups) {
usage(struct testgroup_t *groups, int list_groups) puts("Options are: [--verbose|--quiet|--terse] [--no-fork]");
{ puts(" Specify tests by name, or using a prefix ending with '..'");
puts("Options are: [--verbose|--quiet|--terse] [--no-fork]"); puts(" To skip a test, prefix its name with a colon.");
puts(" Specify tests by name, or using a prefix ending with '..'"); puts(" To enable a disabled test, prefix its name with a plus.");
puts(" To skip a test, prefix its name with a colon."); puts(" Use --list-tests for a list of tests.");
puts(" To enable a disabled test, prefix its name with a plus."); if (list_groups) {
puts(" Use --list-tests for a list of tests."); puts("Known tests are:");
if (list_groups) { tinytest_set_flag_(groups, "..", 1, 0);
puts("Known tests are:"); }
tinytest_set_flag_(groups, "..", 1, 0); exit(0);
}
exit(0);
} }
static int static int process_test_alias(struct testgroup_t *groups, const char *test) {
process_test_alias(struct testgroup_t *groups, const char *test) int i, j, n, r;
{ for (i = 0; cfg_aliases && cfg_aliases[i].name; ++i) {
int i, j, n, r; if (!strcmp(cfg_aliases[i].name, test)) {
for (i=0; cfg_aliases && cfg_aliases[i].name; ++i) { n = 0;
if (!strcmp(cfg_aliases[i].name, test)) { for (j = 0; cfg_aliases[i].tests[j]; ++j) {
n = 0; r = process_test_option(groups, cfg_aliases[i].tests[j]);
for (j = 0; cfg_aliases[i].tests[j]; ++j) { if (r < 0)
r = process_test_option(groups, cfg_aliases[i].tests[j]); return -1;
if (r<0) n += r;
return -1; }
n += r; return n;
} }
return n; }
} printf("No such test alias as @%s!", test);
} return -1;
printf("No such test alias as @%s!",test);
return -1;
} }
static int static int process_test_option(struct testgroup_t *groups, const char *test) {
process_test_option(struct testgroup_t *groups, const char *test) int flag = TT_ENABLED_;
{ int n = 0;
int flag = TT_ENABLED_; if (test[0] == '@') {
int n = 0; return process_test_alias(groups, test + 1);
if (test[0] == '@') { } else if (test[0] == ':') {
return process_test_alias(groups, test + 1); ++test;
} else if (test[0] == ':') { flag = TT_SKIP;
++test; } else if (test[0] == '+') {
flag = TT_SKIP; ++test;
} else if (test[0] == '+') { ++n;
++test; if (!tinytest_set_flag_(groups, test, 0, TT_OFF_BY_DEFAULT)) {
++n; printf("No such test as %s!\n", test);
if (!tinytest_set_flag_(groups, test, 0, TT_OFF_BY_DEFAULT)) { return -1;
printf("No such test as %s!\n", test); }
return -1; } else {
} ++n;
} else { }
++n; if (!tinytest_set_flag_(groups, test, 1, flag)) {
} printf("No such test as %s!\n", test);
if (!tinytest_set_flag_(groups, test, 1, flag)) { return -1;
printf("No such test as %s!\n", test); }
return -1; return n;
}
return n;
} }
void void tinytest_set_aliases(const struct testlist_alias_t *aliases) {
tinytest_set_aliases(const struct testlist_alias_t *aliases) cfg_aliases = aliases;
{
cfg_aliases = aliases;
} }
int int tinytest_main(int c, const char **v, struct testgroup_t *groups) {
tinytest_main(int c, const char **v, struct testgroup_t *groups) int i, j, n = 0;
{
int i, j, n=0;
#ifdef _WIN32 #ifdef _WIN32
const char *sp = strrchr(v[0], '.'); const char *sp = strrchr(v[0], '.');
const char *extension = ""; const char *extension = "";
if (!sp || stricmp(sp, ".exe")) if (!sp || stricmp(sp, ".exe"))
extension = ".exe"; /* Add an exe so CreateProcess will work */ extension = ".exe"; /* Add an exe so CreateProcess will work */
snprintf(commandname, sizeof(commandname), "%s%s", v[0], extension); snprintf(commandname, sizeof(commandname), "%s%s", v[0], extension);
commandname[MAX_PATH]='\0'; commandname[MAX_PATH] = '\0';
#endif #endif
for (i=1; i<c; ++i) { for (i = 1; i < c; ++i) {
if (v[i][0] == '-') { if (v[i][0] == '-') {
if (!strcmp(v[i], "--RUNNING-FORKED")) { if (!strcmp(v[i], "--RUNNING-FORKED")) {
opt_forked = 1; opt_forked = 1;
} else if (!strcmp(v[i], "--no-fork")) { } else if (!strcmp(v[i], "--no-fork")) {
opt_nofork = 1; opt_nofork = 1;
} else if (!strcmp(v[i], "--quiet")) { } else if (!strcmp(v[i], "--quiet")) {
opt_verbosity = -1; opt_verbosity = -1;
verbosity_flag = "--quiet"; verbosity_flag = "--quiet";
} else if (!strcmp(v[i], "--verbose")) { } else if (!strcmp(v[i], "--verbose")) {
opt_verbosity = 2; opt_verbosity = 2;
verbosity_flag = "--verbose"; verbosity_flag = "--verbose";
} else if (!strcmp(v[i], "--terse")) { } else if (!strcmp(v[i], "--terse")) {
opt_verbosity = 0; opt_verbosity = 0;
verbosity_flag = "--terse"; verbosity_flag = "--terse";
} else if (!strcmp(v[i], "--help")) { } else if (!strcmp(v[i], "--help")) {
usage(groups, 0); usage(groups, 0);
} else if (!strcmp(v[i], "--list-tests")) { } else if (!strcmp(v[i], "--list-tests")) {
usage(groups, 1); usage(groups, 1);
} else { } else {
printf("Unknown option %s. Try --help\n",v[i]); printf("Unknown option %s. Try --help\n", v[i]);
return -1; return -1;
} }
} else { } else {
int r = process_test_option(groups, v[i]); int r = process_test_option(groups, v[i]);
if (r<0) if (r < 0)
return -1; return -1;
n += r; n += r;
} }
} }
if (!n) if (!n)
tinytest_set_flag_(groups, "..", 1, TT_ENABLED_); tinytest_set_flag_(groups, "..", 1, TT_ENABLED_);
#ifdef _IONBF #ifdef _IONBF
setvbuf(stdout, NULL, _IONBF, 0); setvbuf(stdout, NULL, _IONBF, 0);
#endif #endif
++in_tinytest_main; ++in_tinytest_main;
for (i=0; groups[i].prefix; ++i) for (i = 0; groups[i].prefix; ++i)
for (j=0; groups[i].cases[j].name; ++j) for (j = 0; groups[i].cases[j].name; ++j)
if (groups[i].cases[j].flags & TT_ENABLED_) if (groups[i].cases[j].flags & TT_ENABLED_)
testcase_run_one(&groups[i], testcase_run_one(&groups[i], &groups[i].cases[j]);
&groups[i].cases[j]);
--in_tinytest_main; --in_tinytest_main;
if (opt_verbosity==0) if (opt_verbosity == 0)
puts(""); puts("");
if (n_bad) if (n_bad)
printf("%d/%d TESTS FAILED. (%d skipped)\n", n_bad, printf("%d/%d TESTS FAILED. (%d skipped)\n", n_bad, n_bad + n_ok,
n_bad+n_ok,n_skipped); n_skipped);
else if (opt_verbosity >= 1) else if (opt_verbosity >= 1)
printf("%d tests ok. (%d skipped)\n", n_ok, n_skipped); printf("%d tests ok. (%d skipped)\n", n_ok, n_skipped);
return (n_bad == 0) ? 0 : 1; return (n_bad == 0) ? 0 : 1;
} }
int int tinytest_get_verbosity_(void) { return opt_verbosity; }
tinytest_get_verbosity_(void)
{ void tinytest_set_test_failed_(void) {
return opt_verbosity; if (opt_verbosity <= 0 && cur_test_name) {
if (opt_verbosity == 0)
puts("");
printf("%s%s: ", cur_test_prefix, cur_test_name);
cur_test_name = NULL;
}
cur_test_outcome = FAIL;
} }
void void tinytest_set_test_skipped_(void) {
tinytest_set_test_failed_(void) if (cur_test_outcome == OK)
{ cur_test_outcome = SKIP;
if (opt_verbosity <= 0 && cur_test_name) {
if (opt_verbosity==0) puts("");
printf("%s%s: ", cur_test_prefix, cur_test_name);
cur_test_name = NULL;
}
cur_test_outcome = FAIL;
} }
void char *tinytest_format_hex_(const void *val_, unsigned long len) {
tinytest_set_test_skipped_(void) const unsigned char *val = (unsigned char *)val_;
{ char *result, *cp;
if (cur_test_outcome==OK) size_t i;
cur_test_outcome = SKIP;
}
char * if (!val)
tinytest_format_hex_(const void *val_, unsigned long len) return strdup("null");
{ if (!(result = (char *)malloc(len * 2 + 1)))
const unsigned char *val = (unsigned char *) val_; return strdup("<allocation failure>");
char *result, *cp; cp = result;
size_t i; for (i = 0; i < len; ++i) {
*cp++ = "0123456789ABCDEF"[val[i] >> 4];
if (!val) *cp++ = "0123456789ABCDEF"[val[i] & 0x0f];
return strdup("null"); }
if (!(result = (char *) malloc(len*2+1))) *cp = 0;
return strdup("<allocation failure>"); return result;
cp = result;
for (i=0;i<len;++i) {
*cp++ = "0123456789ABCDEF"[val[i] >> 4];
*cp++ = "0123456789ABCDEF"[val[i] & 0x0f];
}
*cp = 0;
return result;
} }

View File

@@ -27,15 +27,15 @@
#define TINYTEST_H_INCLUDED_ #define TINYTEST_H_INCLUDED_
/** Flag for a test that needs to run in a subprocess. */ /** Flag for a test that needs to run in a subprocess. */
#define TT_FORK (1<<0) #define TT_FORK (1 << 0)
/** Runtime flag for a test we've decided to skip. */ /** Runtime flag for a test we've decided to skip. */
#define TT_SKIP (1<<1) #define TT_SKIP (1 << 1)
/** Internal runtime flag for a test we've decided to run. */ /** Internal runtime flag for a test we've decided to run. */
#define TT_ENABLED_ (1<<2) #define TT_ENABLED_ (1 << 2)
/** Flag for a test that's off by default. */ /** Flag for a test that's off by default. */
#define TT_OFF_BY_DEFAULT (1<<3) #define TT_OFF_BY_DEFAULT (1 << 3)
/** If you add your own flags, make them start at this point. */ /** If you add your own flags, make them start at this point. */
#define TT_FIRST_USER_FLAG (1<<4) #define TT_FIRST_USER_FLAG (1 << 4)
typedef void (*testcase_fn)(void *); typedef void (*testcase_fn)(void *);
@@ -43,34 +43,37 @@ struct testcase_t;
/** Functions to initialize/teardown a structure for a testcase. */ /** Functions to initialize/teardown a structure for a testcase. */
struct testcase_setup_t { struct testcase_setup_t {
/** Return a new structure for use by a given testcase. */ /** Return a new structure for use by a given testcase. */
void *(*setup_fn)(const struct testcase_t *); void *(*setup_fn)(const struct testcase_t *);
/** Clean/free a structure from setup_fn. Return 1 if ok, 0 on err. */ /** Clean/free a structure from setup_fn. Return 1 if ok, 0 on err. */
int (*cleanup_fn)(const struct testcase_t *, void *); int (*cleanup_fn)(const struct testcase_t *, void *);
}; };
/** A single test-case that you can run. */ /** A single test-case that you can run. */
struct testcase_t { struct testcase_t {
const char *name; /**< An identifier for this case. */ const char *name; /**< An identifier for this case. */
testcase_fn fn; /**< The function to run to implement this case. */ testcase_fn fn; /**< The function to run to implement this case. */
unsigned long flags; /**< Bitfield of TT_* flags. */ unsigned long flags; /**< Bitfield of TT_* flags. */
const struct testcase_setup_t *setup; /**< Optional setup/cleanup fns*/ const struct testcase_setup_t *setup; /**< Optional setup/cleanup fns*/
void *setup_data; /**< Extra data usable by setup function */ void *setup_data; /**< Extra data usable by setup function */
}; };
#define END_OF_TESTCASES { NULL, NULL, 0, NULL, NULL } #define END_OF_TESTCASES \
{ NULL, NULL, 0, NULL, NULL }
/** A group of tests that are selectable together. */ /** A group of tests that are selectable together. */
struct testgroup_t { struct testgroup_t {
const char *prefix; /**< Prefix to prepend to testnames. */ const char *prefix; /**< Prefix to prepend to testnames. */
struct testcase_t *cases; /** Array, ending with END_OF_TESTCASES */ struct testcase_t *cases; /** Array, ending with END_OF_TESTCASES */
}; };
#define END_OF_GROUPS { NULL, NULL} #define END_OF_GROUPS \
{ NULL, NULL }
struct testlist_alias_t { struct testlist_alias_t {
const char *name; const char *name;
const char **tests; const char **tests;
}; };
#define END_OF_ALIASES { NULL, NULL } #define END_OF_ALIASES \
{ NULL, NULL }
/** Implementation: called from a test to indicate failure, before logging. */ /** Implementation: called from a test to indicate failure, before logging. */
void tinytest_set_test_failed_(void); void tinytest_set_test_failed_(void);
@@ -80,16 +83,17 @@ void tinytest_set_test_skipped_(void);
int tinytest_get_verbosity_(void); int tinytest_get_verbosity_(void);
/** Implementation: Set a flag on tests matching a name; returns number /** Implementation: Set a flag on tests matching a name; returns number
* of tests that matched. */ * of tests that matched. */
int tinytest_set_flag_(struct testgroup_t *, const char *, int set, unsigned long); int tinytest_set_flag_(struct testgroup_t *, const char *, int set,
unsigned long);
/** Implementation: Put a chunk of memory into hex. */ /** Implementation: Put a chunk of memory into hex. */
char *tinytest_format_hex_(const void *, unsigned long); char *tinytest_format_hex_(const void *, unsigned long);
/** Set all tests in 'groups' matching the name 'named' to be skipped. */ /** Set all tests in 'groups' matching the name 'named' to be skipped. */
#define tinytest_skip(groups, named) \ #define tinytest_skip(groups, named) \
tinytest_set_flag_(groups, named, 1, TT_SKIP) tinytest_set_flag_(groups, named, 1, TT_SKIP)
/** Run a single testcase in a single group. */ /** Run a single testcase in a single group. */
int testcase_run_one(const struct testgroup_t *,const struct testcase_t *); int testcase_run_one(const struct testgroup_t *, const struct testcase_t *);
void tinytest_set_aliases(const struct testlist_alias_t *aliases); void tinytest_set_aliases(const struct testlist_alias_t *aliases);

View File

@@ -28,182 +28,192 @@
/* Helpers for defining statement-like macros */ /* Helpers for defining statement-like macros */
#define TT_STMT_BEGIN do { #define TT_STMT_BEGIN do {
#define TT_STMT_END } while (0) #define TT_STMT_END \
} \
while (0)
/* Redefine this if your test functions want to abort with something besides /* Redefine this if your test functions want to abort with something besides
* "goto end;" */ * "goto end;" */
#ifndef TT_EXIT_TEST_FUNCTION #ifndef TT_EXIT_TEST_FUNCTION
#define TT_EXIT_TEST_FUNCTION TT_STMT_BEGIN goto end; TT_STMT_END #define TT_EXIT_TEST_FUNCTION \
TT_STMT_BEGIN goto end; \
TT_STMT_END
#endif #endif
/* Redefine this if you want to note success/failure in some different way. */ /* Redefine this if you want to note success/failure in some different way. */
#ifndef TT_DECLARE #ifndef TT_DECLARE
#define TT_DECLARE(prefix, args) \ #define TT_DECLARE(prefix, args) \
TT_STMT_BEGIN \ TT_STMT_BEGIN \
printf("\n %s %s:%d: ",prefix,__FILE__,__LINE__); \ printf("\n %s %s:%d: ", prefix, __FILE__, __LINE__); \
printf args ; \ printf args; \
TT_STMT_END TT_STMT_END
#endif #endif
/* Announce a failure. Args are parenthesized printf args. */ /* Announce a failure. Args are parenthesized printf args. */
#define TT_GRIPE(args) TT_DECLARE("FAIL", args) #define TT_GRIPE(args) TT_DECLARE("FAIL", args)
/* Announce a non-failure if we're verbose. */ /* Announce a non-failure if we're verbose. */
#define TT_BLATHER(args) \ #define TT_BLATHER(args) \
TT_STMT_BEGIN \ TT_STMT_BEGIN \
if (tinytest_get_verbosity_()>1) TT_DECLARE(" OK", args); \ if (tinytest_get_verbosity_() > 1) \
TT_STMT_END TT_DECLARE(" OK", args); \
TT_STMT_END
#define TT_DIE(args) \ #define TT_DIE(args) \
TT_STMT_BEGIN \ TT_STMT_BEGIN \
tinytest_set_test_failed_(); \ tinytest_set_test_failed_(); \
TT_GRIPE(args); \ TT_GRIPE(args); \
TT_EXIT_TEST_FUNCTION; \ TT_EXIT_TEST_FUNCTION; \
TT_STMT_END TT_STMT_END
#define TT_FAIL(args) \ #define TT_FAIL(args) \
TT_STMT_BEGIN \ TT_STMT_BEGIN \
tinytest_set_test_failed_(); \ tinytest_set_test_failed_(); \
TT_GRIPE(args); \ TT_GRIPE(args); \
TT_STMT_END TT_STMT_END
/* Fail and abort the current test for the reason in msg */ /* Fail and abort the current test for the reason in msg */
#define tt_abort_printf(msg) TT_DIE(msg) #define tt_abort_printf(msg) TT_DIE(msg)
#define tt_abort_perror(op) TT_DIE(("%s: %s [%d]",(op),strerror(errno), errno)) #define tt_abort_perror(op) \
TT_DIE(("%s: %s [%d]", (op), strerror(errno), errno))
#define tt_abort_msg(msg) TT_DIE(("%s", msg)) #define tt_abort_msg(msg) TT_DIE(("%s", msg))
#define tt_abort() TT_DIE(("%s", "(Failed.)")) #define tt_abort() TT_DIE(("%s", "(Failed.)"))
/* Fail but do not abort the current test for the reason in msg. */ /* Fail but do not abort the current test for the reason in msg. */
#define tt_fail_printf(msg) TT_FAIL(msg) #define tt_fail_printf(msg) TT_FAIL(msg)
#define tt_fail_perror(op) TT_FAIL(("%s: %s [%d]",(op),strerror(errno), errno)) #define tt_fail_perror(op) \
TT_FAIL(("%s: %s [%d]", (op), strerror(errno), errno))
#define tt_fail_msg(msg) TT_FAIL(("%s", msg)) #define tt_fail_msg(msg) TT_FAIL(("%s", msg))
#define tt_fail() TT_FAIL(("%s", "(Failed.)")) #define tt_fail() TT_FAIL(("%s", "(Failed.)"))
/* End the current test, and indicate we are skipping it. */ /* End the current test, and indicate we are skipping it. */
#define tt_skip() \ #define tt_skip() \
TT_STMT_BEGIN \ TT_STMT_BEGIN \
tinytest_set_test_skipped_(); \ tinytest_set_test_skipped_(); \
TT_EXIT_TEST_FUNCTION; \ TT_EXIT_TEST_FUNCTION; \
TT_STMT_END TT_STMT_END
#define tt_want_(b, msg, fail) \ #define tt_want_(b, msg, fail) \
TT_STMT_BEGIN \ TT_STMT_BEGIN \
if (!(b)) { \ if (!(b)) { \
tinytest_set_test_failed_(); \ tinytest_set_test_failed_(); \
TT_GRIPE(("%s",msg)); \ TT_GRIPE(("%s", msg)); \
fail; \ fail; \
} else { \ } else { \
TT_BLATHER(("%s",msg)); \ TT_BLATHER(("%s", msg)); \
} \ } \
TT_STMT_END TT_STMT_END
/* Assert b, but do not stop the test if b fails. Log msg on failure. */ /* Assert b, but do not stop the test if b fails. Log msg on failure. */
#define tt_want_msg(b, msg) \ #define tt_want_msg(b, msg) tt_want_(b, msg, );
tt_want_(b, msg, );
/* Assert b and stop the test if b fails. Log msg on failure. */ /* Assert b and stop the test if b fails. Log msg on failure. */
#define tt_assert_msg(b, msg) \ #define tt_assert_msg(b, msg) tt_want_(b, msg, TT_EXIT_TEST_FUNCTION);
tt_want_(b, msg, TT_EXIT_TEST_FUNCTION);
/* Assert b, but do not stop the test if b fails. */ /* Assert b, but do not stop the test if b fails. */
#define tt_want(b) tt_want_msg( (b), "want("#b")") #define tt_want(b) tt_want_msg((b), "want(" #b ")")
/* Assert b, and stop the test if b fails. */ /* Assert b, and stop the test if b fails. */
#define tt_assert(b) tt_assert_msg((b), "assert("#b")") #define tt_assert(b) tt_assert_msg((b), "assert(" #b ")")
#define tt_assert_test_fmt_type(a,b,str_test,type,test,printf_type,printf_fmt, \ #define tt_assert_test_fmt_type(a, b, str_test, type, test, printf_type, \
setup_block,cleanup_block,die_on_fail) \ printf_fmt, setup_block, cleanup_block, \
TT_STMT_BEGIN \ die_on_fail) \
type val1_ = (a); \ TT_STMT_BEGIN \
type val2_ = (b); \ type val1_ = (a); \
int tt_status_ = (test); \ type val2_ = (b); \
if (!tt_status_ || tinytest_get_verbosity_()>1) { \ int tt_status_ = (test); \
printf_type print_; \ if (!tt_status_ || tinytest_get_verbosity_() > 1) { \
printf_type print1_; \ printf_type print_; \
printf_type print2_; \ printf_type print1_; \
type value_ = val1_; \ printf_type print2_; \
setup_block; \ type value_ = val1_; \
print1_ = print_; \ setup_block; \
value_ = val2_; \ print1_ = print_; \
setup_block; \ value_ = val2_; \
print2_ = print_; \ setup_block; \
TT_DECLARE(tt_status_?" OK":"FAIL", \ print2_ = print_; \
("assert(%s): " printf_fmt " vs " printf_fmt,\ TT_DECLARE(tt_status_ ? " OK" : "FAIL", \
str_test, print1_, print2_)); \ ("assert(%s): " printf_fmt " vs " printf_fmt, str_test, \
print_ = print1_; \ print1_, print2_)); \
cleanup_block; \ print_ = print1_; \
print_ = print2_; \ cleanup_block; \
cleanup_block; \ print_ = print2_; \
if (!tt_status_) { \ cleanup_block; \
tinytest_set_test_failed_(); \ if (!tt_status_) { \
die_on_fail ; \ tinytest_set_test_failed_(); \
} \ die_on_fail; \
} \ } \
TT_STMT_END } \
TT_STMT_END
#define tt_assert_test_type(a,b,str_test,type,test,fmt,die_on_fail) \ #define tt_assert_test_type(a, b, str_test, type, test, fmt, die_on_fail) \
tt_assert_test_fmt_type(a,b,str_test,type,test,type,fmt, \ tt_assert_test_fmt_type(a, b, str_test, type, test, type, fmt, \
{print_=value_;},{},die_on_fail) { print_ = value_; }, {}, die_on_fail)
#define tt_assert_test_type_opt(a,b,str_test,type,test,fmt,die_on_fail) \ #define tt_assert_test_type_opt(a, b, str_test, type, test, fmt, die_on_fail) \
tt_assert_test_fmt_type(a,b,str_test,type,test,type,fmt, \ tt_assert_test_fmt_type(a, b, str_test, type, test, type, fmt, \
{print_=value_?value_:"<NULL>";},{},die_on_fail) { print_ = value_ ? value_ : "<NULL>"; }, {}, \
die_on_fail)
/* Helper: assert that a op b, when cast to type. Format the values with /* Helper: assert that a op b, when cast to type. Format the values with
* printf format fmt on failure. */ * printf format fmt on failure. */
#define tt_assert_op_type(a,op,b,type,fmt) \ #define tt_assert_op_type(a, op, b, type, fmt) \
tt_assert_test_type(a,b,#a" "#op" "#b,type,(val1_ op val2_),fmt, \ tt_assert_test_type(a, b, #a " " #op " " #b, type, (val1_ op val2_), fmt, \
TT_EXIT_TEST_FUNCTION) TT_EXIT_TEST_FUNCTION)
#define tt_int_op(a,op,b) \ #define tt_int_op(a, op, b) \
tt_assert_test_type(a,b,#a" "#op" "#b,long,(val1_ op val2_), \ tt_assert_test_type(a, b, #a " " #op " " #b, long, (val1_ op val2_), "%ld", \
"%ld",TT_EXIT_TEST_FUNCTION) TT_EXIT_TEST_FUNCTION)
#define tt_uint_op(a,op,b) \ #define tt_uint_op(a, op, b) \
tt_assert_test_type(a,b,#a" "#op" "#b,unsigned long, \ tt_assert_test_type(a, b, #a " " #op " " #b, unsigned long, \
(val1_ op val2_),"%lu",TT_EXIT_TEST_FUNCTION) (val1_ op val2_), "%lu", TT_EXIT_TEST_FUNCTION)
#define tt_ptr_op(a,op,b) \ #define tt_ptr_op(a, op, b) \
tt_assert_test_type(a,b,#a" "#op" "#b,const void*, \ tt_assert_test_type(a, b, #a " " #op " " #b, const void *, (val1_ op val2_), \
(val1_ op val2_),"%p",TT_EXIT_TEST_FUNCTION) "%p", TT_EXIT_TEST_FUNCTION)
#define tt_str_op(a,op,b) \ #define tt_str_op(a, op, b) \
tt_assert_test_type_opt(a,b,#a" "#op" "#b,const char *, \ tt_assert_test_type_opt(a, b, #a " " #op " " #b, const char *, \
(val1_ && val2_ && strcmp(val1_,val2_) op 0),"<%s>", \ (val1_ && val2_ && strcmp(val1_, val2_) op 0), \
TT_EXIT_TEST_FUNCTION) "<%s>", TT_EXIT_TEST_FUNCTION)
#define tt_mem_op(expr1, op, expr2, len) \ #define tt_mem_op(expr1, op, expr2, len) \
tt_assert_test_fmt_type(expr1,expr2,#expr1" "#op" "#expr2, \ tt_assert_test_fmt_type( \
const void *, \ expr1, expr2, #expr1 " " #op " " #expr2, const void *, \
(val1_ && val2_ && memcmp(val1_, val2_, len) op 0), \ (val1_ && val2_ && memcmp(val1_, val2_, len) op 0), char *, "%s", \
char *, "%s", \ { print_ = tinytest_format_hex_(value_, (len)); }, \
{ print_ = tinytest_format_hex_(value_, (len)); }, \ { \
{ if (print_) free(print_); }, \ if (print_) \
TT_EXIT_TEST_FUNCTION \ free(print_); \
); }, \
TT_EXIT_TEST_FUNCTION);
#define tt_want_int_op(a,op,b) \ #define tt_want_int_op(a, op, b) \
tt_assert_test_type(a,b,#a" "#op" "#b,long,(val1_ op val2_),"%ld",(void)0) tt_assert_test_type(a, b, #a " " #op " " #b, long, (val1_ op val2_), "%ld", \
(void)0)
#define tt_want_uint_op(a,op,b) \ #define tt_want_uint_op(a, op, b) \
tt_assert_test_type(a,b,#a" "#op" "#b,unsigned long, \ tt_assert_test_type(a, b, #a " " #op " " #b, unsigned long, \
(val1_ op val2_),"%lu",(void)0) (val1_ op val2_), "%lu", (void)0)
#define tt_want_ptr_op(a,op,b) \ #define tt_want_ptr_op(a, op, b) \
tt_assert_test_type(a,b,#a" "#op" "#b,const void*, \ tt_assert_test_type(a, b, #a " " #op " " #b, const void *, (val1_ op val2_), \
(val1_ op val2_),"%p",(void)0) "%p", (void)0)
#define tt_want_str_op(a,op,b) \ #define tt_want_str_op(a, op, b) \
tt_assert_test_type(a,b,#a" "#op" "#b,const char *, \ tt_assert_test_type(a, b, #a " " #op " " #b, const char *, \
(strcmp(val1_,val2_) op 0),"<%s>",(void)0) (strcmp(val1_, val2_) op 0), "<%s>", (void)0)
#define tt_want_mem_op(expr1, op, expr2, len) \ #define tt_want_mem_op(expr1, op, expr2, len) \
tt_assert_test_fmt_type(expr1,expr2,#expr1" "#op" "#expr2, \ tt_assert_test_fmt_type( \
const void *, \ expr1, expr2, #expr1 " " #op " " #expr2, const void *, \
(val1_ && val2_ && memcmp(val1_, val2_, len) op 0), \ (val1_ && val2_ && memcmp(val1_, val2_, len) op 0), char *, "%s", \
char *, "%s", \ { print_ = tinytest_format_hex_(value_, (len)); }, \
{ print_ = tinytest_format_hex_(value_, (len)); }, \ { \
{ if (print_) free(print_); }, \ if (print_) \
(void)0 \ free(print_); \
); }, \
(void)0);
#endif #endif

File diff suppressed because it is too large Load Diff

View File

@@ -4,7 +4,8 @@
* To Public License, Version 2, as published by Sam Hocevar. See * To Public License, Version 2, as published by Sam Hocevar. See
* http://sam.zoy.org/wtfpl/COPYING for more details. * http://sam.zoy.org/wtfpl/COPYING for more details.
* *
* I2P-Bote: 5m77dFKGEq6~7jgtrfw56q3t~SmfwZubmGdyOLQOPoPp8MYwsZ~pfUCwud6LB1EmFxkm4C3CGlzq-hVs9WnhUV * I2P-Bote:
* 5m77dFKGEq6~7jgtrfw56q3t~SmfwZubmGdyOLQOPoPp8MYwsZ~pfUCwud6LB1EmFxkm4C3CGlzq-hVs9WnhUV
* we are the Borg. */ * we are the Borg. */
#ifndef LIBSAM3_H #ifndef LIBSAM3_H
#define LIBSAM3_H #define LIBSAM3_H
@@ -20,51 +21,54 @@ extern "C" {
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
extern int libsam3_debug; extern int libsam3_debug;
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
#define SAM3_HOST_DEFAULT (NULL) #define SAM3_HOST_DEFAULT (NULL)
#define SAM3_PORT_DEFAULT (0) #define SAM3_PORT_DEFAULT (0)
#define SAM3_DESTINATION_TRANSIENT (NULL) #define SAM3_DESTINATION_TRANSIENT (NULL)
#define SAM3_PUBKEY_SIZE (516)
#define SAM3_PRIVKEY_SIZE (884)
#define SAM3_PUBKEY_SIZE (516)
#define SAM3_CERT_SIZE (100)
#define SAM3_PRIVKEY_MIN_SIZE (884)
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/* returns fd or -1 */ /* returns fd or -1 */
/* 'ip': host IP; can be NULL */ /* 'ip': host IP; can be NULL */
extern int sam3tcpConnect (const char *hostname, int port, uint32_t *ip); extern int sam3tcpConnect(const char *hostname, int port, uint32_t *ip);
extern int sam3tcpConnectIP (uint32_t ip, int port); extern int sam3tcpConnectIP(uint32_t ip, int port);
/* <0: error; 0: ok */ /* <0: error; 0: ok */
extern int sam3tcpDisconnect (int fd); extern int sam3tcpDisconnect(int fd);
/* <0: error; 0: ok */ /* <0: error; 0: ok */
extern int sam3tcpSetTimeoutSend (int fd, int timeoutms); extern int sam3tcpSetTimeoutSend(int fd, int timeoutms);
/* <0: error; 0: ok */ /* <0: error; 0: ok */
extern int sam3tcpSetTimeoutReceive (int fd, int timeoutms); extern int sam3tcpSetTimeoutReceive(int fd, int timeoutms);
/* <0: error; 0: ok */ /* <0: error; 0: ok */
/* sends the whole buffer */ /* sends the whole buffer */
extern int sam3tcpSend (int fd, const void *buf, size_t bufSize); extern int sam3tcpSend(int fd, const void *buf, size_t bufSize);
/* <0: received (-res) bytes; read error */ /* <0: received (-res) bytes; read error */
/* can return less that requesten bytes even if `allowPartial` is 0 when connection is closed */ /* can return less that requesten bytes even if `allowPartial` is 0 when
extern ssize_t sam3tcpReceiveEx (int fd, void *buf, size_t bufSize, int allowPartial); * connection is closed */
extern ssize_t sam3tcpReceiveEx(int fd, void *buf, size_t bufSize,
int allowPartial);
extern ssize_t sam3tcpReceive (int fd, void *buf, size_t bufSize); extern ssize_t sam3tcpReceive(int fd, void *buf, size_t bufSize);
extern int sam3tcpPrintf (int fd, const char *fmt, ...) __attribute__((format(printf,2,3))); extern int sam3tcpPrintf(int fd, const char *fmt, ...)
__attribute__((format(printf, 2, 3)));
extern int sam3tcpReceiveStr (int fd, char *dest, size_t maxSize); extern int sam3tcpReceiveStr(int fd, char *dest, size_t maxSize);
/* pass NULL for 'localhost' and 0 for 7655 */ /* pass NULL for 'localhost' and 0 for 7655 */
/* 'ip': host IP; can be NULL */ /* 'ip': host IP; can be NULL */
extern int sam3udpSendTo (const char *hostname, int port, const void *buf, size_t bufSize, uint32_t *ip); extern int sam3udpSendTo(const char *hostname, int port, const void *buf,
extern int sam3udpSendToIP (uint32_t ip, int port, const void *buf, size_t bufSize); size_t bufSize, uint32_t *ip);
extern int sam3udpSendToIP(uint32_t ip, int port, const void *buf,
size_t bufSize);
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
typedef struct SAMFieldList { typedef struct SAMFieldList {
@@ -73,16 +77,16 @@ typedef struct SAMFieldList {
struct SAMFieldList *next; struct SAMFieldList *next;
} SAMFieldList; } SAMFieldList;
extern void sam3FreeFieldList(SAMFieldList *list);
extern void sam3FreeFieldList (SAMFieldList *list); extern void sam3DumpFieldList(const SAMFieldList *list);
extern void sam3DumpFieldList (const SAMFieldList *list);
/* read and parse SAM reply */ /* read and parse SAM reply */
/* NULL: error; else: list of fields */ /* NULL: error; else: list of fields */
/* first item is always 2-word reply, with first word in name and second in value */ /* first item is always 2-word reply, with first word in name and second in
extern SAMFieldList *sam3ReadReply (int fd); * value */
extern SAMFieldList *sam3ReadReply(int fd);
extern SAMFieldList *sam3ParseReply (const char *rep); extern SAMFieldList *sam3ParseReply(const char *rep);
/* /*
* example: * example:
@@ -92,17 +96,17 @@ extern SAMFieldList *sam3ParseReply (const char *rep);
* VALUE: NULL or 'OK' * VALUE: NULL or 'OK'
* returns bool * returns bool
*/ */
extern int sam3IsGoodReply (const SAMFieldList *list, const char *r0, const char *r1, const char *field, const char *value); extern int sam3IsGoodReply(const SAMFieldList *list, const char *r0,
const char *r1, const char *field,
extern const char *sam3FindField (const SAMFieldList *list, const char *field); const char *value);
extern const char *sam3FindField(const SAMFieldList *list, const char *field);
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/* pass NULL for 'localhost' and 0 for 7656 */ /* pass NULL for 'localhost' and 0 for 7656 */
/* returns <0 on error or socket fd on success */ /* returns <0 on error or socket fd on success */
extern int sam3Handshake (const char *hostname, int port, uint32_t *ip); extern int sam3Handshake(const char *hostname, int port, uint32_t *ip);
extern int sam3HandshakeIP (uint32_t ip, int port); extern int sam3HandshakeIP(uint32_t ip, int port);
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
typedef enum { typedef enum {
@@ -111,14 +115,25 @@ typedef enum {
SAM3_SESSION_STREAM SAM3_SESSION_STREAM
} Sam3SessionType; } Sam3SessionType;
typedef enum {
DSA_SHA1,
ECDSA_SHA256_P256,
ECDSA_SHA384_P384,
ECDSA_SHA512_P521,
EdDSA_SHA512_Ed25519
} Sam3SigType;
typedef struct Sam3Session { typedef struct Sam3Session {
Sam3SessionType type; Sam3SessionType type;
Sam3SigType sigType;
int fd; int fd;
char privkey[SAM3_PRIVKEY_SIZE+1]; // destination private key (asciiz) char privkey[SAM3_PRIVKEY_MIN_SIZE + 1]; // destination private key (asciiz)
char pubkey[SAM3_PUBKEY_SIZE+1]; // destination public key (asciiz) char pubkey[SAM3_PUBKEY_SIZE + SAM3_CERT_SIZE +
1]; // destination public key (asciiz)
char channel[66]; // name of this sam session (asciiz) char channel[66]; // name of this sam session (asciiz)
char destkey[SAM3_PUBKEY_SIZE+1]; // for DGRAM sessions (asciiz) char destkey[SAM3_PUBKEY_SIZE + SAM3_CERT_SIZE +
1]; // for DGRAM sessions (asciiz)
// int destsig;
char error[32]; // error message (asciiz) char error[32]; // error message (asciiz)
uint32_t ip; uint32_t ip;
int port; // this will be changed to UDP port for DRAM/RAW (can be 0) int port; // this will be changed to UDP port for DRAM/RAW (can be 0)
@@ -126,12 +141,13 @@ typedef struct Sam3Session {
int fwd_fd; int fwd_fd;
} Sam3Session; } Sam3Session;
typedef struct Sam3Connection { typedef struct Sam3Connection {
Sam3Session *ses; Sam3Session *ses;
struct Sam3Connection *next; struct Sam3Connection *next;
int fd; int fd;
char destkey[SAM3_PUBKEY_SIZE+1]; // remote destination public key (asciiz) char destkey[SAM3_PUBKEY_SIZE + SAM3_CERT_SIZE +
1]; // remote destination public key (asciiz)
int destcert;
char error[32]; // error message (asciiz) char error[32]; // error message (asciiz)
} Sam3Connection; } Sam3Connection;
@@ -144,19 +160,26 @@ typedef struct Sam3Connection {
* 'params' can be NULL * 'params' can be NULL
* see http://www.i2p2.i2p/i2cp.html#options for common options, * see http://www.i2p2.i2p/i2cp.html#options for common options,
* and http://www.i2p2.i2p/streaming.html#options for STREAM options * and http://www.i2p2.i2p/streaming.html#options for STREAM options
* if result<0: error, 'ses' fields are undefined, no need to call sam3CloseSession() * if result<0: error, 'ses' fields are undefined, no need to call
* if result==0: ok, all 'ses' fields are filled * sam3CloseSession() if result==0: ok, all 'ses' fields are filled
* TODO: don't clear 'error' field on error (and set it to something meaningful) * TODO: don't clear 'error' field on error (and set it to something meaningful)
*/ */
extern int sam3CreateSession (Sam3Session *ses, const char *hostname, int port, const char *privkey, Sam3SessionType type, extern int sam3CreateSession(Sam3Session *ses, const char *hostname, int port,
const char *params); const char *privkey, Sam3SessionType type,
Sam3SigType sigType, const char *params);
/* /*
* close SAM session (and all it's connections) * close SAM session (and all it's connections)
* returns <0 on error, 0 on ok * returns <0 on error, 0 on ok
* 'ses' must be properly initialized * 'ses' must be properly initialized
*/ */
extern int sam3CloseSession (Sam3Session *ses); extern int sam3CloseSession(Sam3Session *ses);
/*
* Check to make sure that the destination in use is of a valid length, returns
* 1 if true and 0 if false.
*/
int sam3CheckValidKeyLength(const char *pubkey);
/* /*
* open stream connection to 'destkey' endpoint * open stream connection to 'destkey' endpoint
@@ -165,7 +188,7 @@ extern int sam3CloseSession (Sam3Session *ses);
* you still have to call sam3CloseSession() on failure * you still have to call sam3CloseSession() on failure
* sets ses->error on error * sets ses->error on error
*/ */
extern Sam3Connection *sam3StreamConnect (Sam3Session *ses, const char *destkey); extern Sam3Connection *sam3StreamConnect(Sam3Session *ses, const char *destkey);
/* /*
* accepts stream connection and sets 'destkey' * accepts stream connection and sets 'destkey'
@@ -175,7 +198,7 @@ extern Sam3Connection *sam3StreamConnect (Sam3Session *ses, const char *destkey)
* sets ses->error on error * sets ses->error on error
* note that there is no timeouts for now, but you can use sam3tcpSetTimeout*() * note that there is no timeouts for now, but you can use sam3tcpSetTimeout*()
*/ */
extern Sam3Connection *sam3StreamAccept (Sam3Session *ses); extern Sam3Connection *sam3StreamAccept(Sam3Session *ses);
/* /*
* sets up forwarding stream connection * sets up forwarding stream connection
@@ -184,7 +207,7 @@ extern Sam3Connection *sam3StreamAccept (Sam3Session *ses);
* sets ses->error on error * sets ses->error on error
* note that there is no timeouts for now, but you can use sam3tcpSetTimeout*() * note that there is no timeouts for now, but you can use sam3tcpSetTimeout*()
*/ */
extern int sam3StreamForward (Sam3Session *ses, const char *hostname, int port); extern int sam3StreamForward(Sam3Session *ses, const char *hostname, int port);
/* /*
* close SAM connection * close SAM connection
@@ -192,8 +215,7 @@ extern int sam3StreamForward (Sam3Session *ses, const char *hostname, int port);
* 'conn' must be properly initialized * 'conn' must be properly initialized
* 'conn' is invalid after call * 'conn' is invalid after call
*/ */
extern int sam3CloseConnection (Sam3Connection *conn); extern int sam3CloseConnection(Sam3Connection *conn);
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/* /*
@@ -203,7 +225,8 @@ extern int sam3CloseConnection (Sam3Connection *conn);
* will not set 'error' field * will not set 'error' field
* returns <0 on error, 0 on ok * returns <0 on error, 0 on ok
*/ */
extern int sam3GenerateKeys (Sam3Session *ses, const char *hostname, int port); extern int sam3GenerateKeys(Sam3Session *ses, const char *hostname, int port,
int sigType);
/* /*
* do name lookup (something like gethostbyname()) * do name lookup (something like gethostbyname())
@@ -212,8 +235,8 @@ extern int sam3GenerateKeys (Sam3Session *ses, const char *hostname, int port);
* will set 'error' field * will set 'error' field
* returns <0 on error, 0 on ok * returns <0 on error, 0 on ok
*/ */
extern int sam3NameLookup (Sam3Session *ses, const char *hostname, int port, const char *name); extern int sam3NameLookup(Sam3Session *ses, const char *hostname, int port,
const char *name);
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/* /*
@@ -224,32 +247,34 @@ extern int sam3NameLookup (Sam3Session *ses, const char *hostname, int port, con
* sets ses->error on error * sets ses->error on error
* don't send datagrams bigger than 31KB! * don't send datagrams bigger than 31KB!
*/ */
extern int sam3DatagramSend (Sam3Session *ses, const char *destkey, const void *buf, size_t bufsize); extern int sam3DatagramSend(Sam3Session *ses, const char *destkey,
const void *buf, size_t bufsize);
/* /*
* receives datagram and sets 'destkey' to source pubkey (if not RAW) * receives datagram and sets 'destkey' to source pubkey (if not RAW)
* returns <0 on error (buffer too small is error too) or number of bytes written to 'buf' * returns <0 on error (buffer too small is error too) or number of bytes
* you still have to call sam3CloseSession() on failure * written to 'buf' you still have to call sam3CloseSession() on failure sets
* sets ses->error on error * ses->error on error will necer receive datagrams bigger than 31KB (32KB for
* will necer receive datagrams bigger than 31KB (32KB for RAW) * RAW)
*/ */
extern ssize_t sam3DatagramReceive (Sam3Session *ses, void *buf, size_t bufsize); extern ssize_t sam3DatagramReceive(Sam3Session *ses, void *buf, size_t bufsize);
/* /*
* generate random sam channel name * generate random sam channel name
* return the size of the string * return the size of the string
*/ */
extern size_t sam3GenChannelName (char *dest, size_t minlen, size_t maxlen); extern size_t sam3GenChannelName(char *dest, size_t minlen, size_t maxlen);
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// NOT including '\0' terminator // NOT including '\0' terminator
static inline size_t sam3Base32EncodedLength (size_t size) { return (((size+5-1)/5)*8); } static inline size_t sam3Base32EncodedLength(size_t size) {
return (((size + 5 - 1) / 5) * 8);
}
// output 8 bytes for every 5 input // output 8 bytes for every 5 input
// return size or <0 on error // return size or <0 on error
extern ssize_t sam3Base32Encode (char *dest, size_t destsz, const void *srcbuf, size_t srcsize); extern ssize_t sam3Base32Encode(char *dest, size_t destsz, const void *srcbuf,
size_t srcsize);
#ifdef __cplusplus #ifdef __cplusplus
} }

File diff suppressed because it is too large Load Diff

View File

@@ -6,7 +6,8 @@
* To Public License, Version 2, as published by Sam Hocevar. See * To Public License, Version 2, as published by Sam Hocevar. See
* http://sam.zoy.org/wtfpl/COPYING for more details. * http://sam.zoy.org/wtfpl/COPYING for more details.
* *
* I2P-Bote: 5m77dFKGEq6~7jgtrfw56q3t~SmfwZubmGdyOLQOPoPp8MYwsZ~pfUCwud6LB1EmFxkm4C3CGlzq-hVs9WnhUV * I2P-Bote:
* 5m77dFKGEq6~7jgtrfw56q3t~SmfwZubmGdyOLQOPoPp8MYwsZ~pfUCwud6LB1EmFxkm4C3CGlzq-hVs9WnhUV
* we are the Borg. */ * we are the Borg. */
#ifndef LIBSAM3A_H #ifndef LIBSAM3A_H
#define LIBSAM3A_H #define LIBSAM3A_H
@@ -32,26 +33,22 @@ extern "C" {
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
extern int libsam3a_debug; extern int libsam3a_debug;
////////////////////////////////////////////////////////////////////////////////
#define SAM3A_HOST_DEFAULT (NULL)
#define SAM3A_PORT_DEFAULT (0)
#define SAM3A_DESTINATION_TRANSIENT (NULL)
#define SAM3A_PUBKEY_SIZE (516)
#define SAM3A_PRIVKEY_SIZE (884)
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
#define SAM3A_HOST_DEFAULT (NULL) extern uint64_t sam3atimeval2ms(const struct timeval *tv);
#define SAM3A_PORT_DEFAULT (0) extern void sam3ams2timeval(struct timeval *tv, uint64_t ms);
#define SAM3A_DESTINATION_TRANSIENT (NULL)
#define SAM3A_PUBKEY_SIZE (516)
#define SAM3A_PRIVKEY_SIZE (884)
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
extern uint64_t sam3atimeval2ms (const struct timeval *tv); extern int sam3aIsValidPubKey(const char *key);
extern void sam3ams2timeval (struct timeval *tv, uint64_t ms); extern int sam3aIsValidPrivKey(const char *key);
////////////////////////////////////////////////////////////////////////////////
extern int sam3aIsValidPubKey (const char *key);
extern int sam3aIsValidPrivKey (const char *key);
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
typedef struct Sam3ASession Sam3ASession; typedef struct Sam3ASession Sam3ASession;
@@ -79,38 +76,42 @@ typedef struct {
/** session callback functions */ /** session callback functions */
typedef struct { typedef struct {
void (*cbError) (Sam3ASession *ses); /** called on error */ void (*cbError)(Sam3ASession *ses); /** called on error */
void (*cbCreated) (Sam3ASession *ses); /** called when we created the session */ void (*cbCreated)(
void (*cbDisconnected) (Sam3ASession *ses); /* call when closed; will called only after cbCreated() */ Sam3ASession *ses); /** called when we created the session */
void (*cbDatagramRead) (Sam3ASession *ses, const void *buf, int bufsize); /* called when we got a datagram; bufsize >= 0; destkey set */ void (*cbDisconnected)(Sam3ASession *ses); /* call when closed; will called
void (*cbDestroy) (Sam3ASession *ses); /* called when fd is already closed, but keys is not cleared */ only after cbCreated() */
void (*cbDatagramRead)(Sam3ASession *ses, const void *buf,
int bufsize); /* called when we got a datagram; bufsize
>= 0; destkey set */
void (*cbDestroy)(Sam3ASession *ses); /* called when fd is already closed, but
keys is not cleared */
} Sam3ASessionCallbacks; } Sam3ASessionCallbacks;
struct Sam3ASession { struct Sam3ASession {
Sam3ASessionType type; /** session type */ Sam3ASessionType type; /** session type */
int fd; /** socket file descriptor */ int fd; /** socket file descriptor */
int cancelled; /** fd was shutdown()ed, but not closed yet */ int cancelled; /** fd was shutdown()ed, but not closed yet */
char privkey[SAM3A_PRIVKEY_SIZE+1]; /** private key (asciiz) */ char privkey[SAM3A_PRIVKEY_SIZE + 1]; /** private key (asciiz) */
char pubkey[SAM3A_PUBKEY_SIZE+1]; /** public key (asciiz) */ char pubkey[SAM3A_PUBKEY_SIZE + 1]; /** public key (asciiz) */
char channel[66]; /** channel name (asciiz) */ char channel[66]; /** channel name (asciiz) */
char destkey[SAM3A_PUBKEY_SIZE+1]; /** for DGRAM sessions (asciiz) */ char destkey[SAM3A_PUBKEY_SIZE + 1]; /** for DGRAM sessions (asciiz) */
char error[64]; /** error message (asciiz) */ char error[64]; /** error message (asciiz) */
uint32_t ip; /** ipv4 address of sam api interface */ uint32_t ip; /** ipv4 address of sam api interface */
int port; /** UDP port for DRAM/RAW (can be 0) */ int port; /** UDP port for DRAM/RAW (can be 0) */
Sam3AConnection *connlist; /** list of opened connections */ Sam3AConnection *connlist; /** list of opened connections */
/** begin internal members */ /** begin internal members */
// for async i/o // for async i/o
Sam3AIO aio; Sam3AIO aio;
void (*cbAIOProcessorR) (Sam3ASession *ses); // internal void (*cbAIOProcessorR)(Sam3ASession *ses); // internal
void (*cbAIOProcessorW) (Sam3ASession *ses); // internal void (*cbAIOProcessorW)(Sam3ASession *ses); // internal
int callDisconnectCB; int callDisconnectCB;
char *params; // will be cleared only by sam3aCloseSession() char *params; // will be cleared only by sam3aCloseSession()
int timeoutms; int timeoutms;
/** end internal members */ /** end internal members */
Sam3ASessionCallbacks cb; Sam3ASessionCallbacks cb;
void *udata; void *udata;
}; };
@@ -118,22 +119,24 @@ struct Sam3ASession {
/** connection callbacks for data sockets */ /** connection callbacks for data sockets */
typedef struct { typedef struct {
/** called on error */ /** called on error */
void (*cbError) (Sam3AConnection *ct); void (*cbError)(Sam3AConnection *ct);
/** called when closed or only after cbConnected()/cbAccepted(); note that force disconnect is ok */ /** called when closed or only after cbConnected()/cbAccepted(); note that
void (*cbDisconnected) (Sam3AConnection *ct); * force disconnect is ok */
void (*cbDisconnected)(Sam3AConnection *ct);
/** called when connected */ /** called when connected */
void (*cbConnected) (Sam3AConnection *ct); void (*cbConnected)(Sam3AConnection *ct);
/** called instead of cbConnected() for sam3aStreamAccept*(), destkey filled with remote destination */ /** called instead of cbConnected() for sam3aStreamAccept*(), destkey filled
void (*cbAccepted) (Sam3AConnection *ct); * with remote destination */
/** send callback, data sent, can add new data; will be called after connect/accept */ void (*cbAccepted)(Sam3AConnection *ct);
void (*cbSent) (Sam3AConnection *ct); /** send callback, data sent, can add new data; will be called after
* connect/accept */
void (*cbSent)(Sam3AConnection *ct);
/** read callback, data read from socket (bufsize is always > 0) */ /** read callback, data read from socket (bufsize is always > 0) */
void (*cbRead) (Sam3AConnection *ct, const void *buf, int bufsize); void (*cbRead)(Sam3AConnection *ct, const void *buf, int bufsize);
/** fd already closed, but keys is not cleared */ /** fd already closed, but keys is not cleared */
void (*cbDestroy) (Sam3AConnection *ct); void (*cbDestroy)(Sam3AConnection *ct);
} Sam3AConnectionCallbacks; } Sam3AConnectionCallbacks;
struct Sam3AConnection { struct Sam3AConnection {
/** parent session */ /** parent session */
Sam3ASession *ses; Sam3ASession *ses;
@@ -141,39 +144,37 @@ struct Sam3AConnection {
/** file descriptor */ /** file descriptor */
int fd; int fd;
int cancelled; // fd was shutdown()ed, but not closed yet int cancelled; // fd was shutdown()ed, but not closed yet
char destkey[SAM3A_PUBKEY_SIZE+1]; // (asciiz) char destkey[SAM3A_PUBKEY_SIZE + 1]; // (asciiz)
char error[32]; // (asciiz) char error[32]; // (asciiz)
/** begin internal members */ /** begin internal members */
// for async i/o // for async i/o
Sam3AIO aio; Sam3AIO aio;
void (*cbAIOProcessorR) (Sam3AConnection *ct); // internal void (*cbAIOProcessorR)(Sam3AConnection *ct); // internal
void (*cbAIOProcessorW) (Sam3AConnection *ct); // internal void (*cbAIOProcessorW)(Sam3AConnection *ct); // internal
int callDisconnectCB; int callDisconnectCB;
char *params; // will be cleared only by sam3aCloseConnection() char *params; // will be cleared only by sam3aCloseConnection()
int timeoutms; int timeoutms;
/** end internal members */ /** end internal members */
/** callbacks */ /** callbacks */
Sam3AConnectionCallbacks cb; Sam3AConnectionCallbacks cb;
/** user data */ /** user data */
void *udata; void *udata;
}; };
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/* /*
* check if session is active (i.e. have opened socket) * check if session is active (i.e. have opened socket)
* returns bool * returns bool
*/ */
extern int sam3aIsActiveSession (const Sam3ASession *ses); extern int sam3aIsActiveSession(const Sam3ASession *ses);
/* /*
* check if connection is active (i.e. have opened socket) * check if connection is active (i.e. have opened socket)
* returns bool * returns bool
*/ */
extern int sam3aIsActiveConnection (const Sam3AConnection *conn); extern int sam3aIsActiveConnection(const Sam3AConnection *conn);
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/* /*
@@ -188,35 +189,40 @@ extern int sam3aIsActiveConnection (const Sam3AConnection *conn);
* 'params' can be NULL * 'params' can be NULL
* see http://www.i2p2.i2p/i2cp.html#options for common options, * see http://www.i2p2.i2p/i2cp.html#options for common options,
* and http://www.i2p2.i2p/streaming.html#options for STREAM options * and http://www.i2p2.i2p/streaming.html#options for STREAM options
* if result<0: error, 'ses' fields are undefined, no need to call sam3aCloseSession() * if result<0: error, 'ses' fields are undefined, no need to call
* if result==0: ok, all 'ses' fields are filled * sam3aCloseSession() if result==0: ok, all 'ses' fields are filled
* TODO: don't clear 'error' field on error (and set it to something meaningful) * TODO: don't clear 'error' field on error (and set it to something meaningful)
*/ */
extern int sam3aCreateSessionEx (Sam3ASession *ses, const Sam3ASessionCallbacks *cb, extern int sam3aCreateSessionEx(Sam3ASession *ses,
const char *hostname, int port, const char *privkey, Sam3ASessionType type, const char *params, int timeoutms); const Sam3ASessionCallbacks *cb,
const char *hostname, int port,
const char *privkey, Sam3ASessionType type,
const char *params, int timeoutms);
static inline int sam3aCreateSession (Sam3ASession *ses, const Sam3ASessionCallbacks *cb, static inline int sam3aCreateSession(Sam3ASession *ses,
const char *hostname, int port, const char *privkey, Sam3ASessionType type) const Sam3ASessionCallbacks *cb,
{ const char *hostname, int port,
const char *privkey,
Sam3ASessionType type) {
return sam3aCreateSessionEx(ses, cb, hostname, port, privkey, type, NULL, -1); return sam3aCreateSessionEx(ses, cb, hostname, port, privkey, type, NULL, -1);
} }
/* returns <0 on error, 0 if no, >0 if yes */ /* returns <0 on error, 0 if no, >0 if yes */
extern int sam3aIsHaveActiveConnections (const Sam3ASession *ses); extern int sam3aIsHaveActiveConnections(const Sam3ASession *ses);
/* /*
* close SAM session (and all it's connections) * close SAM session (and all it's connections)
* returns <0 on error, 0 on ok * returns <0 on error, 0 on ok
* 'ses' must be properly initialized * 'ses' must be properly initialized
*/ */
extern int sam3aCloseSession (Sam3ASession *ses); extern int sam3aCloseSession(Sam3ASession *ses);
/* /*
* cancel SAM session (and all it's connections), but don't free() or clear anything except fds * cancel SAM session (and all it's connections), but don't free() or clear
* returns <0 on error, 0 on ok * anything except fds returns <0 on error, 0 on ok 'ses' must be properly
* 'ses' must be properly initialized * initialized
*/ */
extern int sam3aCancelSession (Sam3ASession *ses); extern int sam3aCancelSession(Sam3ASession *ses);
/* /*
* open stream connection to 'destkey' endpoint * open stream connection to 'destkey' endpoint
@@ -224,10 +230,14 @@ extern int sam3aCancelSession (Sam3ASession *ses);
* returns <0 on error * returns <0 on error
* sets ses->error on memory or socket creation error * sets ses->error on memory or socket creation error
*/ */
extern Sam3AConnection *sam3aStreamConnectEx (Sam3ASession *ses, const Sam3AConnectionCallbacks *cb, const char *destkey, extern Sam3AConnection *sam3aStreamConnectEx(Sam3ASession *ses,
int timeoutms); const Sam3AConnectionCallbacks *cb,
const char *destkey,
int timeoutms);
static inline Sam3AConnection *sam3aStreamConnect (Sam3ASession *ses, const Sam3AConnectionCallbacks *cb, const char *destkey) { static inline Sam3AConnection *
sam3aStreamConnect(Sam3ASession *ses, const Sam3AConnectionCallbacks *cb,
const char *destkey) {
return sam3aStreamConnectEx(ses, cb, destkey, -1); return sam3aStreamConnectEx(ses, cb, destkey, -1);
} }
@@ -239,9 +249,12 @@ static inline Sam3AConnection *sam3aStreamConnect (Sam3ASession *ses, const Sam3
* sets ses->error on error * sets ses->error on error
* note that there is no timeouts for now, but you can use sam3atcpSetTimeout*() * note that there is no timeouts for now, but you can use sam3atcpSetTimeout*()
*/ */
extern Sam3AConnection *sam3aStreamAcceptEx (Sam3ASession *ses, const Sam3AConnectionCallbacks *cb, int timeoutms); extern Sam3AConnection *sam3aStreamAcceptEx(Sam3ASession *ses,
const Sam3AConnectionCallbacks *cb,
int timeoutms);
static inline Sam3AConnection *sam3aStreamAccept (Sam3ASession *ses, const Sam3AConnectionCallbacks *cb) { static inline Sam3AConnection *
sam3aStreamAccept(Sam3ASession *ses, const Sam3AConnectionCallbacks *cb) {
return sam3aStreamAcceptEx(ses, cb, -1); return sam3aStreamAcceptEx(ses, cb, -1);
} }
@@ -251,7 +264,7 @@ static inline Sam3AConnection *sam3aStreamAccept (Sam3ASession *ses, const Sam3A
* 'conn' must be properly initialized * 'conn' must be properly initialized
* 'conn' is invalid after call * 'conn' is invalid after call
*/ */
extern int sam3aCloseConnection (Sam3AConnection *conn); extern int sam3aCloseConnection(Sam3AConnection *conn);
/* /*
* cancel SAM connection, but don't free() or clear anything except fd * cancel SAM connection, but don't free() or clear anything except fd
@@ -259,17 +272,16 @@ extern int sam3aCloseConnection (Sam3AConnection *conn);
* 'conn' must be properly initialized * 'conn' must be properly initialized
* 'conn' is invalid after call * 'conn' is invalid after call
*/ */
extern int sam3aCancelConnection (Sam3AConnection *conn); extern int sam3aCancelConnection(Sam3AConnection *conn);
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/* /*
* send data * send data
* this function can be used in cbSent() callback * this function can be used in cbSent() callback
* *
* return: <0: error; 0: ok * return: <0: error; 0: ok
*/ */
extern int sam3aSend (Sam3AConnection *conn, const void *data, int datasize); extern int sam3aSend(Sam3AConnection *conn, const void *data, int datasize);
/* /*
* sends datagram to 'destkey' endpoint * sends datagram to 'destkey' endpoint
@@ -279,16 +291,15 @@ extern int sam3aSend (Sam3AConnection *conn, const void *data, int datasize);
* sets ses->error on error * sets ses->error on error
* don't send datagrams bigger than 31KB! * don't send datagrams bigger than 31KB!
*/ */
extern int sam3aDatagramSend (Sam3ASession *ses, const char *destkey, const void *buf, int bufsize); extern int sam3aDatagramSend(Sam3ASession *ses, const char *destkey,
const void *buf, int bufsize);
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/* /*
* generate random channel name * generate random channel name
* dest should be at least (maxlen+1) bytes big * dest should be at least (maxlen+1) bytes big
*/ */
extern int sam3aGenChannelName (char *dest, int minlen, int maxlen); extern int sam3aGenChannelName(char *dest, int minlen, int maxlen);
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/* /*
@@ -298,27 +309,31 @@ extern int sam3aGenChannelName (char *dest, int minlen, int maxlen);
* cbCreated callback will be called when keys generated * cbCreated callback will be called when keys generated
* returns <0 on error, 0 on ok * returns <0 on error, 0 on ok
*/ */
extern int sam3aGenerateKeysEx (Sam3ASession *ses, const Sam3ASessionCallbacks *cb, const char *hostname, int port, extern int sam3aGenerateKeysEx(Sam3ASession *ses,
int timeoutms); const Sam3ASessionCallbacks *cb,
const char *hostname, int port, int timeoutms);
static inline int sam3aGenerateKeys (Sam3ASession *ses, const Sam3ASessionCallbacks *cb, const char *hostname, int port) { static inline int sam3aGenerateKeys(Sam3ASession *ses,
const Sam3ASessionCallbacks *cb,
const char *hostname, int port) {
return sam3aGenerateKeysEx(ses, cb, hostname, port, -1); return sam3aGenerateKeysEx(ses, cb, hostname, port, -1);
} }
/* /*
* do name lookup (something like gethostbyname()) * do name lookup (something like gethostbyname())
* fills 'destkey' only * fills 'destkey' only
* you should call sam3aCloseSession() on 'ses' * you should call sam3aCloseSession() on 'ses'
* cbCreated callback will be called when keys generated, ses->destkey will be set * cbCreated callback will be called when keys generated, ses->destkey will be
* returns <0 on error, 0 on ok * set returns <0 on error, 0 on ok
*/ */
extern int sam3aNameLookupEx (Sam3ASession *ses, const Sam3ASessionCallbacks *cb, const char *hostname, int port, extern int sam3aNameLookupEx(Sam3ASession *ses, const Sam3ASessionCallbacks *cb,
const char *name, int timeoutms); const char *hostname, int port, const char *name,
int timeoutms);
static inline int sam3aNameLookup (Sam3ASession *ses, const Sam3ASessionCallbacks *cb, const char *hostname, int port, static inline int sam3aNameLookup(Sam3ASession *ses,
const char *name) const Sam3ASessionCallbacks *cb,
{ const char *hostname, int port,
const char *name) {
return sam3aNameLookupEx(ses, cb, hostname, port, name, -1); return sam3aNameLookupEx(ses, cb, hostname, port, name, -1);
} }
@@ -330,20 +345,20 @@ static inline int sam3aNameLookup (Sam3ASession *ses, const Sam3ASessionCallback
* returns maxfd or -1 * returns maxfd or -1
* TODO: should keep fd count so it will not exceed FD_SETSIZE! * TODO: should keep fd count so it will not exceed FD_SETSIZE!
*/ */
extern int sam3aAddSessionToFDS (Sam3ASession *ses, int maxfd, fd_set *rds, fd_set *wrs); extern int sam3aAddSessionToFDS(Sam3ASession *ses, int maxfd, fd_set *rds,
fd_set *wrs);
/* /*
* process session i/o (and all session connections i/o) * process session i/o (and all session connections i/o)
* should be called after successful select() * should be called after successful select()
*/ */
extern void sam3aProcessSessionIO (Sam3ASession *ses, fd_set *rds, fd_set *wrs); extern void sam3aProcessSessionIO(Sam3ASession *ses, fd_set *rds, fd_set *wrs);
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/* return malloc()ed buffer and len in 'plen' (if plen != NULL) */ /* return malloc()ed buffer and len in 'plen' (if plen != NULL) */
extern char *sam3PrintfVA (int *plen, const char *fmt, va_list app); extern char *sam3PrintfVA(int *plen, const char *fmt, va_list app);
extern char *sam3Printf (int *plen, const char *fmt, ...) __attribute__((format(printf,2,3))); extern char *sam3Printf(int *plen, const char *fmt, ...)
__attribute__((format(printf, 2, 3)));
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@@ -4,7 +4,8 @@
* To Public License, Version 2, as published by Sam Hocevar. See * To Public License, Version 2, as published by Sam Hocevar. See
* http://sam.zoy.org/wtfpl/COPYING for more details. * http://sam.zoy.org/wtfpl/COPYING for more details.
* *
* I2P-Bote: 5m77dFKGEq6~7jgtrfw56q3t~SmfwZubmGdyOLQOPoPp8MYwsZ~pfUCwud6LB1EmFxkm4C3CGlzq-hVs9WnhUV * I2P-Bote:
* 5m77dFKGEq6~7jgtrfw56q3t~SmfwZubmGdyOLQOPoPp8MYwsZ~pfUCwud6LB1EmFxkm4C3CGlzq-hVs9WnhUV
* we are the Borg. */ * we are the Borg. */
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
@@ -15,8 +16,7 @@
#include "../../src/ext/tinytest_macros.h" #include "../../src/ext/tinytest_macros.h"
#include "../../src/libsam3/libsam3.h" #include "../../src/libsam3/libsam3.h"
static int testb32(const char *src, const char *res) {
static int testb32 (const char *src, const char *res) {
size_t dlen = sam3Base32EncodedLength(strlen(src)), len; size_t dlen = sam3Base32EncodedLength(strlen(src)), len;
char dest[128]; char dest[128];
// //
@@ -41,11 +41,11 @@ void test_b32_encode(void *data) {
tt_assert(testb32("fooba", "mzxw6ytb")); tt_assert(testb32("fooba", "mzxw6ytb"));
tt_assert(testb32("foobar", "mzxw6ytboi======")); tt_assert(testb32("foobar", "mzxw6ytboi======"));
end: end:;
;
} }
struct testcase_t b32_tests[] = { struct testcase_t b32_tests[] = {{
{ "encode", test_b32_encode, }, "encode",
END_OF_TESTCASES test_b32_encode,
}; },
END_OF_TESTCASES};

View File

@@ -5,10 +5,7 @@
extern struct testcase_t b32_tests[]; extern struct testcase_t b32_tests[];
struct testgroup_t test_groups[] = { struct testgroup_t test_groups[] = {{"b32/", b32_tests}, END_OF_GROUPS};
{ "b32/", b32_tests },
END_OF_GROUPS
};
int main(int argc, const char **argv) { int main(int argc, const char **argv) {
return tinytest_main(argc, argv, test_groups); return tinytest_main(argc, argv, test_groups);