/* * Active Router Transport Protocol (ARTP) implementation - demo of using * Copyright (c) 2004, Tomas Rebok * All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the "BSD License" which is * distributed with the software in the file LICENSE. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the BSD * License for more details. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "artp.h" /* macro used for changing characters into its upper case */ #define TO_UPPER(c) c = ((c >= 97) && (c <= 122)) ? c - 32 : c; /* structure for storing information about created sessions */ struct Tsesns { struct sockaddr_in receiver; struct in_addr address; SID_TYPE sid; }; /* structure passed as a argument for session's thread */ struct Targument { struct sockaddr_in sender; SID_TYPE sid; }; /* session array */ struct Tsesns sesns[50]; int sesns_count = 0; int port = 12006; int retval = 0; char config_file[50]; /* maximal strings size */ #define MAX_STRINGY 10000 /* maximal control items count */ #define MAX_CTRL_COUNT 10 /* Function used for reading input strings */ int nacti(char *retezec) { int delka; char znak; delka = 0; while ((znak = getchar()) != '\n') retezec[delka++] = znak; retezec[delka++] = '\0'; return 0; } /* function used for showing established sessions */ int vypis_sessions() { int i; for (i = 0; i < sesns_count; i++) { printf("%d ... Receiver: %s, SID: %d\n", i + 1, inet_ntoa(sesns[i].receiver.sin_addr), sesns[i].sid); } return 0; } /* initialize socket */ int init_socket(int port) { struct sockaddr_in address; int sock; memset(&address, 0, sizeof(struct sockaddr_in)); address.sin_family = AF_INET; address.sin_addr.s_addr = htonl(INADDR_ANY); address.sin_port = htons(port); /* Creates a socket. */ sock = socket(AF_INET, SOCK_DGRAM, 0); if (sock < 0) { printf("Error opening datagram socket\n"); return -1; } /* Bind the socket to the port. */ if (bind(sock, (struct sockaddr*) &address, sizeof(struct sockaddr_in)) < 0) { printf("Error binding datagram socket\n"); return -1; } /* init ARTP */ if (artp_init(sock, config_file) != 0) { printf("Error starting threads\n"); return -1; } printf("Connection established on port %d.\n", port); return sock; } /* function used for sending requests for new sessions. */ int send_session_request(SID_TYPE sid, struct sockaddr_in *receiver) { struct artp_dgram pckt; struct payload_CTRL ctrl; char value[15]; ctrl.control = (struct control_type *) malloc(sizeof(struct control_type)); ctrl.count = 1; ctrl.control[0].type = REQUEST; ctrl.control[0].optid = 100; strcpy(value, "NEW_SESSION"); ctrl.control[0].value = (char *) malloc((strlen(value) + 1) * sizeof(char)); strcpy(ctrl.control[0].value, value); ctrl.control[0].valuesize = strlen(value); pckt.type = CTRL; pckt.payload.ctrl = ctrl; artp_send_dgram(&pckt, sid, (struct sockaddr *) receiver); artp_free_dgram(&pckt); return 0; } /* function used for acknowledging requests of new sessions. */ int send_session_ack(SID_TYPE sid, struct sockaddr_in *receiver) { struct artp_dgram pckt; struct payload_CTRL ctrl; char value[20]; ctrl.control = (struct control_type *) malloc(sizeof(struct control_type)); ctrl.count = 1; ctrl.control[0].type = REPLY; ctrl.control[0].optid = 100; strcpy(value, "ACK_NEW_SESSION\0"); ctrl.control[0].value = (char *) malloc((strlen(value) + 1) * sizeof(char)); strcpy(ctrl.control[0].value, value); ctrl.control[0].valuesize = strlen(value); pckt.type = CTRL; pckt.payload.ctrl = ctrl; artp_send_dgram(&pckt, sid, (struct sockaddr *) receiver); artp_free_dgram(&pckt); return 0; } /* function used for sending requests for closing sessions. */ int send_session_dest(SID_TYPE sid, struct sockaddr_in *receiver) { struct artp_dgram pckt; struct payload_CTRL ctrl; char value[15]; ctrl.control = (struct control_type *) malloc(sizeof(struct control_type)); ctrl.count = 1; ctrl.control[0].type = REQUEST; ctrl.control[0].optid = 101; strcpy(value, "DEST_SESSION\0"); ctrl.control[0].value = (char *) malloc((strlen(value) + 1) * sizeof(char)); strcpy(ctrl.control[0].value, value); ctrl.control[0].valuesize = strlen(value); pckt.type = CTRL; pckt.payload.ctrl = ctrl; artp_send_dgram(&pckt, sid, (struct sockaddr *) receiver); artp_free_dgram(&pckt); return 0; } /* thread for sessions */ void *session_thread(void *arg) { struct sockaddr_in sender; struct sockaddr_in receiver; struct in_addr address; struct artp_dgram packet; struct Targument *argument; char option[20]; char filename[100]; SID_TYPE sid; SID_TYPE sid2; int fd; int volba; int i; int zapsano = 1; double last_incoming = -1; double time; struct timeval current_time; double celk_size = 0; /* parse given argument */ argument = (struct Targument *) arg; sender = argument -> sender; sid = argument -> sid; printf("\n\n1 ... write received data on the screen\n"); printf("2 ... write received data to the file\n"); printf("3 ... write received data to the file without comments and signature\n"); printf("4 ... count received data's size only\n"); printf("5 ... forward received data without any change\n"); printf("6 ... forward received data transferred to upper case\n"); printf("\nWhat shall I do? : "); nacti(option); volba = atoi(option); if ((volba == 2) || (volba == 3)) { printf("\nFile's name: "); nacti(filename); fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_SYNC, S_IRWXU | S_IRWXG); } if ((volba == 5) || (volba == 6)) { printf("Receiver's IP address: "); nacti(option); inet_aton(option, &address); receiver.sin_family = AF_INET; receiver.sin_addr = address; receiver.sin_port = htons(port); if (artp_get_sid((struct sockaddr *) &receiver, &sid2) != 0) { printf("There isn't any session's id available!\n"); exit(-2); } send_session_request(sid2, &receiver); } while (1) { gettimeofday(¤t_time, 0); time = current_time.tv_sec + current_time.tv_usec / 1000000.0; /* wait for new datagram */ if ((zapsano == 1) && (artp_receive_dgram(sid, (struct sockaddr *) &sender, &packet) < 0)) { usleep(1); if ((last_incoming != -1) && (time - last_incoming > 5000000)) { exit(0); } continue; } zapsano = 0; last_incoming = time; /* shall we destroy this session? */ if ((packet.type == CTRL) && (packet.payload.ctrl.control[0].type == REQUEST) && (packet.payload.ctrl.control[0].optid == 101) && (memcmp(packet.payload.ctrl.control[0].value, "DEST_SESSION", packet.payload.ctrl.control[0].valuesize) == 0)) { printf("Destroying session... \n"); artp_destroy_connection(sid, (struct sockaddr *) &sender); if ((volba == 5) || (volba == 6)) { send_session_dest(sid2, &receiver); artp_destroy_connection(sid2, (struct sockaddr *) &receiver); } exit(0); } /* do not receive control datagrams */ if (packet.type == CTRL) { printf("\nThis demo shows control datagrams ONLY on the screen!\n"); printf("Received CTRL (count %d):\n", packet.payload.ctrl.count); for (i = 0; i < packet.payload.ctrl.count; i++) { printf("Ctrl: %d, ", i + 1); switch (packet.payload.ctrl.control[i].type) { case REQUEST: printf("Type: REQUEST, "); break; case REPLY: printf("Type: REPLY, "); break; } printf(" id. number: %d, value: ", packet.payload.ctrl.control[i].optid); fflush(stdout); write(1, packet.payload.ctrl.control[i].value, packet.payload.ctrl.control[i].valuesize); printf("\n"); } printf("\n"); printf("Nothing will be written into the file or counted.\n"); artp_free_dgram(&packet); zapsano = 1; continue; } /* show/write/resend received datagram */ switch (volba) { case 1: printf("Signature: ");fflush(stdout); write(1, packet.payload.data.sigdata, packet.payload.data.sigsz); printf("\n"); printf("Data: "); fflush(stdout); write(1, packet.payload.data.encdata, packet.payload.data.encsz); zapsano = 1; printf("\n"); break; case 2: write(fd, "\nSignature: ", 9); write(fd, packet.payload.data.sigdata, packet.payload.data.sigsz); write(fd, "\nData: ", 7); case 3: write(fd, packet.payload.data.encdata, packet.payload.data.encsz); zapsano = 1; break; case 4: celk_size += (packet.payload.data.encsz / 1000000.0); printf("Received size (without signature): %0.6f MB\n", celk_size); zapsano = 1; break; case 6: for (i = 0; i < packet.payload.data.sigsz; i++) TO_UPPER(packet.payload.data.sigdata[i]); for (i = 0; i < packet.payload.data.encsz; i++) TO_UPPER(packet.payload.data.encdata[i]); case 5: if (artp_send_dgram(&packet, sid2, (struct sockaddr *) &receiver) == 0) zapsano = 1; break; } if (zapsano == 1) artp_free_dgram(&packet); } } /* thread used for listening requests for new sessions */ void *incoming_thread(void *arg) { struct artp_dgram packet; struct sockaddr_in *sender; struct sockaddr_in undeliverable_receiver; SID_TYPE sid; struct Targument argument; int i; pthread_t session[10]; int sessions_threads = 0; while (1) { /* are there any undeliverable requests? */ if (artp_get_undlvr_session(&sid, (struct sockaddr *) &undeliverable_receiver) == 0) { printf("\nCannot send initial packet to %s, sid %d.\n", inet_ntoa(undeliverable_receiver.sin_addr), sid); printf("Giving it up...\n"); } /* receive any datagram */ if (artp_receive_any_dgram(&sid, (struct sockaddr **) &sender, &packet) < 0) { usleep(10); continue; } /* show all information */ switch (packet.type) { case DATA: printf("Received DATA no. %d:\n", packet.payload.data.dseq); printf("Signature of size %d: %s\n", packet.payload.data.sigsz, packet.payload.data.sigdata); printf("Data of size %d: %s\n", packet.payload.data.encsz, packet.payload.data.encdata); printf("\n"); break; case CTRL: printf("Received CTRL (count %d):\n", packet.payload.ctrl.count); for (i = 0; i < packet.payload.ctrl.count; i++) { printf("Opt: %d, ", i + 1); switch (packet.payload.ctrl.control[i].type) { case REQUEST: printf("Type: REQUEST, "); break; case REPLY: printf("Type: REPLY, "); break; } if ((packet.payload.ctrl.control[i].optid == 100) && ((memcmp(packet.payload.ctrl.control[i].value, "NEW_SESSION", packet.payload.ctrl.control[i].valuesize) == 0) || (memcmp(packet.payload.ctrl.control[i].value, "ACK_NEW_SESSION", packet.payload.ctrl.control[i].valuesize) == 0))) { if (packet.payload.ctrl.control[i].type == REQUEST) send_session_ack(sid, sender); sesns[sesns_count].sid = sid; sesns[sesns_count].receiver.sin_family = AF_INET; sesns[sesns_count].receiver.sin_addr = sender -> sin_addr; sesns[sesns_count].receiver.sin_port = sender -> sin_port; if (artp_prepare_connection(sid, (struct sockaddr *) sender) == 0) { ++sesns_count; if (packet.payload.ctrl.control[i].type==REQUEST) { /* run new thread only for requests */ argument.sender = *sender; argument.sid = sid; pthread_create(&session[sessions_threads++], NULL, session_thread, (void *) &argument); } } else printf("Session already exists or some other error happened.\n"); } } printf("\n"); break; default: break; } /* unallocate necessary information */ artp_free_dgram(&packet); free(sender); } } int main(int argc, char *argv[]) { struct artp_dgram pckt; struct payload_DATA data; struct payload_CTRL ctrl; int option = -1; int volba; int velikost; char nacteno[10]; char filename[50]; int sckt; int i; SID_TYPE sid; struct sockaddr_in receiver; struct in_addr address; int fd; char ip_prijemce[16]; char opt; char znak; DSEQ_TYPE current_dseq = 0; pthread_t incoming; config_file[0] = '\0'; /* parse given options */ while ((opt = getopt(argc, argv, "p:c:h")) != -1) { switch (opt) { case 'p': port = atoi(optarg); break; case 'c': strcpy(config_file, optarg); break; case 'h': default : printf("Usage: %s [-p port] [-c config_file]\n", argv[0]); return -1; break; } } sckt = init_socket(port); if (sckt < 0) return -1; /* start receiving thread */ if (pthread_create(&incoming, NULL, incoming_thread, NULL) != 0) return -1; data.sigdata = (char *) malloc(MAX_STRINGY * sizeof(char)); data.encdata = (char *) malloc(MAX_STRINGY * sizeof(char)); ctrl.control = (struct control_type *) malloc(MAX_CTRL_COUNT * sizeof(struct control_type)); while (option != 0) { printf("\n\nDemo for testing ARTP protocol:\n"); printf("====================================\n"); printf("1 ... show established sessions\n"); printf("2 ... try to establish new session\n"); printf("3 ... destroy previously established session\n"); printf("4 ... send ARTP data packet\n"); printf("5 ... send ARTP control packet\n"); printf("6 ... send the whole file as one ARTP packet\n"); printf("7 ... send whole file as packets of given size\n"); printf("9 ... listen mode\n"); printf("\n0 ... end\n"); printf("\n\n\tYour choice? : "); nacti(nacteno); option = atoi(nacteno); if (nacteno[0] == '\0') option = -1; printf("\n"); switch (option) { case 0: printf("Bye!!! :-)\n\n"); break; case 1: if (sesns_count == 0) { printf("There isn't any established session!!!\n"); break; } vypis_sessions(); break; case 2: printf("Receiver's IP address: "); nacti(ip_prijemce); inet_aton(ip_prijemce, &address); receiver.sin_family = AF_INET; receiver.sin_addr = address; receiver.sin_port = htons(port); if (artp_get_sid((struct sockaddr *) &receiver, &sid) != 0) { printf("There isn't any session's id available!\n"); break; } send_session_request(sid, &receiver); break; case 3: if (sesns_count == 0) { printf("There isn't any established session!!!\n"); break; } vypis_sessions(); printf("\nWhich session would you like to destroy? : "); nacti(nacteno); volba = atoi(nacteno); if ((volba > sesns_count) || (volba < 1)) break; send_session_dest(sesns[volba-1].sid, &sesns[volba-1].receiver); artp_destroy_connection(sesns[volba-1].sid, (struct sockaddr *) &sesns[volba-1].receiver); for (i = volba - 1; i < sesns_count - 1; i++) sesns[i] = sesns[i + 1]; --sesns_count; break; case 4: if (sesns_count == 0) { printf("There isn't any established session!!!\n"); break; } vypis_sessions(); printf("Who do you want to send it to? : "); nacti(nacteno); volba = atoi(nacteno); if ((volba > sesns_count) || (volba < 1)) break; printf("Signature (max %d): ", MAX_STRINGY); nacti(data.sigdata); data.sigsz = strlen(data.sigdata); printf("Data (max %d): ", MAX_STRINGY); nacti(data.encdata); data.encsz = strlen(data.encdata); data.dseq = ++current_dseq; pckt.type = DATA; pckt.payload.data = data; if (artp_send_dgram(&pckt, sesns[volba-1].sid, (struct sockaddr *) &sesns[volba-1].receiver) != 0) printf("Error in packet's sending\n"); break; case 5: if (sesns_count == 0) { printf("There isn't any established session!!!\n"); break; } vypis_sessions(); printf("Who do you want to send it to? : "); nacti(nacteno); volba = atoi(nacteno); if ((volba > sesns_count) || (volba < 1)) break; printf("How many options do you want to send? (1..%d): ", MAX_CTRL_COUNT); nacti(nacteno); ctrl.count = atoi(nacteno); for (i = 0; i < ctrl.count; i++) ctrl.control[i].value = (char *) malloc(MAX_STRINGY * sizeof(char)); for (i = 0; i < ctrl.count; i++) { printf("Type of %d option (Q=request, R=reply) : ",i+1); nacti(nacteno); znak = nacteno[0]; switch (znak) { case 'q': case 'Q': ctrl.control[i].type = REQUEST; break; case 'r': case 'R': ctrl.control[i].type = REPLY; break; } printf("%d option's identification number : ", i + 1); nacti(nacteno); ctrl.control[i].optid = atoi(nacteno); printf("%d option's value (max %d): ", i + 1, MAX_STRINGY); nacti(ctrl.control[i].value); ctrl.control[i].valuesize = strlen(ctrl.control[i].value); } pckt.type = CTRL; pckt.payload.ctrl = ctrl; artp_send_dgram(&pckt, sesns[volba-1].sid, (struct sockaddr *) &sesns[volba-1].receiver); break; case 6: if (sesns_count == 0) { printf("There isn't any established session!!!\n"); break; } vypis_sessions(); printf("Who do you want to send it to? : "); nacti(nacteno); volba = atoi(nacteno); if ((volba > sesns_count) || (volba < 1)) break; printf("Default signature (max %d): ", MAX_STRINGY); nacti(data.sigdata); data.sigsz = strlen(data.sigdata); printf("Filename that data will be read from (size <= %d): ", MAX_STRINGY); nacti(filename); fd = open(filename, O_RDONLY); if (fd < 1) { printf("Cannot open given file!\n"); break; } i = lseek(fd, 0, SEEK_END); lseek(fd, 0, SEEK_SET); data.encsz = read(fd, data.encdata, i); close(fd); pckt.type = DATA; pckt.payload.data = data; artp_send_dgram(&pckt, sesns[volba-1].sid, (struct sockaddr *) &sesns[volba-1].receiver); break; case 7: if (sesns_count == 0) { printf("There isn't any established session!!!\n"); break; } vypis_sessions(); printf("Who do you want to send it to? : "); nacti(nacteno); volba = atoi(nacteno); if ((volba > sesns_count) || (volba < 1)) break; printf("Default signature (max %d): ", MAX_STRINGY); nacti(data.sigdata); data.sigsz = strlen(data.sigdata); printf("Filename that data will be read from: "); nacti(filename); fd = open(filename, O_RDONLY); if (fd < 1) { printf("Cannot open given file!\n"); break; } printf("Each packet's size (max %d): ", MAX_STRINGY); nacti(nacteno); velikost = atoi(nacteno); while ((data.encsz = read(fd, data.encdata, velikost)) != 0) { data.dseq = ++current_dseq; pckt.type = DATA; pckt.payload.data = data; while ((retval = artp_send_dgram(&pckt, sesns[volba-1].sid, (struct sockaddr *) &sesns[volba-1].receiver)) == E_FULL_BUFFER) usleep(1); if (retval == E_DEAD_SESSION) { printf("Sorry, but session's DEAD... :-(\n"); exit(-1); } } close(fd); break; case 9: while (1) sleep(10); break; default: printf("Bad choice! Try it one again...\n"); } } free(data.sigdata); data.sigdata = NULL; free(data.encdata); data.encdata = NULL; free(ctrl.control); ctrl.control = NULL; return 0; } /* vim: set ts=4 : */