According to https://github.com/signal11/hidapi/issues/72 HIDAPI ought to be thread safe on Linux machines. However, I can't get it working at all. This is what I do:
#ifdef WIN32
#include <windows.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <stdlib.h>
#include <assert.h>
#include "hidapi.h"
hid_device *handle;
static void *TaskCode(void *argument)
{
int res;
//hid_device *handle;
unsigned char buf[64];
// res = hid_init();
// if( res == -1 )
// {
// return (void*)1;
// }
//
// handle = hid_open(0x0911, 0x251c, NULL);
// if( handle == NULL )
// {
// return (void*)2;
// }
printf( "while 2\n");
while( 1 )
{
memset( buf, 64, 0 );
res = hid_read(handle, buf, 0);
if( res == -1 )
{
return (void*)3;
}
printf( "received %d bytes\n", res);
for (int i = 0; i < res; i++)
printf("Byte %d: %02x ", i+1, buf[i]);
//printf( "%02x ", buf[0]);
fflush(stdout);
}
return (void*)0;
}
int main(int argc, char* argv[])
{
int res;
//hid_device *handle;
unsigned char buf[65];
res = hid_init();
if( res == -1 )
{
return 1;
}
handle = hid_open(0x0911, 0x251c, NULL);
if( handle == NULL )
{
return 2;
}
hid_set_nonblocking( handle, 0 );
pthread_t thread;
int rc = pthread_create(&thread, NULL, TaskCode, NULL);
printf( "while 1\n");
while(1)
{
int a = getchar();
if( a == 'a')
{
// Get Device Type (cmd 0x82). The first byte is the report number (0x0).
buf[0] = 0x0;
buf[1] = 0x82;
res = hid_write(handle, buf, 65);
if( res != -1 )
printf( "write ok, transferred %d bytes\n", res );
else
{
printf( "write error\n" );
char* str = hid_error(handle);
printf( "error: %s\n", str );
return 1;
}
}
else if( a== 'b')
break;
}
void* trc;
rc = pthread_join(thread, &trc);
printf( "rc code: %d\n", (int)trc );
// Finalize the hidapi library
res = hid_exit();
return 0;
}
If I don't use the global handle, I get 'write error' every time. If I do, as in the example, formally everything works but hid_read always returns 0 bytes... Of course, if I do simple hid_write() followed by hid_read(), I'll get the correct reply to the command 0x82 as intended. I'm really lost here, am I overlooking something?
EDIT: to clarify, zero bytes return also for everything, incl. buttons on mouse etc. So it seems to work but the data buffer is always zero bytes.
Shame on me, a dumb mistake. The code should be:
memset( buf, 0, 64 );
res = hid_read(handle, buf, 64);
and then it works. Should sleep more and write less!
Related
I'm using nftw(file tree walk) for traversing a dir(which has sub-directories and files). I've passed a directory using CLI function. Now I need to store the leaf files and dirs(empty dirs) into a linked list and print them out. I've create a function for nftw called as disp & passed it to nftw so that it'll print out some info about the files. The linked list stores the info of file produced by stat & for printing the linked Linked list printll function is used.
For files I can check that typeflag == FTW_F and then enter the following but how do I check empty directories in nftw and add them to the linked list?
I've tried the following
#define _XOPEN_SOURCE 500
#include <stdio.h>
#include <ftw.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <dirent.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
typedef struct node{
long ino; //Inode number
long f_size; //file size
long a_tm; //Access time
long m_tm; //Modify time
long c_tm; //change time
struct node *next;
}node;
node *tmp = NULL;
static node *head = NULL;
void printll(node *head);
//display function
static int disp(const char *fpath,
const struct stat *s,
int typeflag,
struct FTW *ftw);
//Function to create linked list
static int linked(const char *fpath,
const struct stat *s,
int typeflag,
struct FTW *ftw);
/* ------------------Main---------------------*/
int main(int argc, char *argv[]){
int flags = 0;
if(argc > 2 && strchr(argv[2], 'd') != NULL)
flags |= FTW_DEPTH;
printf("File_type\tF_size\t\tPath\t\t\t\t\t\t\tInode\n");
if(nftw((argc < 2) ? "." : argv[1], disp, 20, flags) == -1) {
perror("nftw");
return -1;
}
printf("\n");
// nftw((argc < 2) ? "." : argv[1], linked, 20, flags);
printll(tmp);
exit(EXIT_SUCCESS);
}
static int disp(const char *fpath,
const struct stat *s,
int typeflag,
struct FTW *ftw){
printf("%-3s\t\t%7jd\t\t%-40s\t\t%ld\n",
(typeflag == FTW_D) ? "d" : (typeflag == FTW_F) ? "f": "???",
s->st_size, fpath, s->st_ino);
struct dirent *r;
if(typeflag == FTW_F){ //How to check empty dirs here?
if(head == NULL){
head = malloc(sizeof(node));
head->ino = s->st_ino;
head->f_size = s->st_size;
head->a_tm = s->st_atime;
head->m_tm = s->st_mtime;
head->c_tm = s->st_ctime;
head->next = NULL;
tmp = head;
} else if(head != NULL) {
if(tmp != NULL){
node *ptr = malloc(sizeof(node));
ptr->ino = s->st_ino;
ptr->f_size = s->st_size;
ptr->a_tm = s->st_atime;
ptr->m_tm = s->st_mtime;
ptr->c_tm = s->st_ctime;
ptr->next = NULL;
tmp->next = ptr;
tmp = tmp->next;
}
}
while(tmp != NULL){
printf("%ld\n", tmp->ino);
printf("%ld\n", tmp->f_size);
printf("%ld\n", tmp->a_tm);
printf("%ld\n", tmp->m_tm);
printf("%ld\n", tmp->c_tm);
tmp = tmp->next;
}
}
return 0;
}
void printll(node *head){
node *ptr;
if(head == NULL)
printf("The linked list is NULL\n");
ptr = head;
while(ptr != NULL){
printf("%ld\n", ptr->ino);
printf("%ld\n", ptr->f_size);
printf("%ld\n", ptr->a_tm);
printf("%ld\n", ptr->m_tm);
printf("%ld\n", ptr->c_tm);
ptr = ptr->next;
}
}
Here's the code for creaiting the linked list using ftw
#define _XOPEN_SOURCE 500
#include <stdio.h>
#include <libgen.h>
#include <ftw.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <dirent.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
typedef struct node{
long ino;
long f_size;
long a_tm;
long m_tm;
long c_tm;
struct node *next;
}node;
node *c, *tmp = NULL, *loc;
static node *head = NULL;
void printll(node *head); //printing of linked list
static int disp(const char *fpath,
const struct stat *s,
int typeflag,
struct FTW *ftw);
static int linked(const char *fpath,
const struct stat *s,
int typeflag,
struct FTW *ftw);
void add_at_end(node *p);
/* ------------------Main---------------------*/
int main(int argc, char *argv[]){
int flags = 0;
if(argc > 2 && strchr(argv[2], 'd') != NULL)
flags |= FTW_DEPTH;
printf("File_type\tF_size\t\tPath\t\t\t\t\t\t\tInode\n");
if(nftw((argc < 2) ? "." : argv[1], disp, 20, flags) == -1) {
perror("nftw");
return -1;
}
nftw((argc < 2) ? "." : argv[1], linked, 20, flags);
printf("\n");
printll(tmp);
int num, fd;
char f_name[100], dest[100], str_ent[100];
char c, dl;
struct stat fb;
while(1){
printf("1. Add a file\n");
printf("2. Delete a file\n");
printf("3. Add a directory\n");
printf("4. Delete a directory\n");
printf("Enter the operation num to perform\n");
scanf(" %d", &num);
switch(num){
case 1:
printf("File Name: ");
scanf("%s", f_name);
printf("Destination: ");
scanf("%s", dest);
strcat(dest, f_name);
open(dest, O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
printf("File %s is successfully added.\n", f_name);
printf("Do you want to write to this file (Y/N)? \n");
scanf(" %c", &c);
if(c == 'y' || c == 'Y'){
FILE *f;
f = fopen(dest, "w");
printf("How many lines do you want to enter: ");
scanf("%d", &num);
printf("Enter content\n");
for(int i = 0; i < num+1; i++){
fgets(str_ent, sizeof str_ent, stdin);
fputs(str_ent, f);
}
printf("The content you entered is written to the file\n");
fclose(f);
stat(dest, &fb);
loc = malloc(sizeof(node));
loc->ino = fb.st_ino;
loc->f_size = fb.st_size;
loc->a_tm = fb.st_atime;
loc->m_tm = fb.st_mtime;
loc->c_tm = fb.st_ctime;
loc->next = NULL;
node *b;
b = tmp;
while(b->next != NULL)
b = b->next;
b->next = loc;
printf("File added to linked list successfully\n");
break;
} else if( c == 'n' || c == 'N'){
stat(dest, &fb);
loc = malloc(sizeof(node));
loc->ino = fb.st_ino;
loc->f_size = fb.st_size;
loc->a_tm = fb.st_atime;
loc->m_tm = fb.st_mtime;
loc->c_tm = fb.st_ctime;
loc->next = NULL;
node *b;
b = tmp;
while(b->next != NULL)
b = b->next;
b->next = loc;
printf("File added to linked list successfully\n");
free(loc);
break;
}
case 2:
printf("File Name: ");
scanf("%s", f_name);
printf("Destination: ");
scanf("%s", dest);
strcat(dest, f_name);
stat(dest, &fb);
printf("The inode for removed file is: %ld\n", fb.st_ino);
loc = malloc(sizeof(node));
loc->ino = fb.st_ino;
loc->f_size = fb.st_size;
loc->a_tm = fb.st_atime;
loc->m_tm = fb.st_mtime;
loc->c_tm = fb.st_ctime;
loc->next = NULL;
if(loc->ino == tmp->ino){
tmp = tmp->next;
printf("The node is shifted to next and break is here\n");
break;
} else {
node *bu, *cu;
bu = tmp; //tmp
cu = tmp; //tmp2
while(cu->ino != loc->ino){
bu = cu;
cu = cu->next;
}
bu->next = cu->next;
free(cu);
cu = NULL;
unlink(dest);
printf("File %s has been removed & linked list it updated.\n", f_name);
break;
}
case 3:
printf("Dir Name: ");
scanf("%s", f_name);
printf("\nDestination: ");
scanf("%s", dest);
strcat(dest, f_name);
mkdir(dest, 00700);
stat(dest, &fb);
loc = malloc(sizeof(node));
loc->ino = fb.st_ino;
loc->f_size = fb.st_size;
loc->a_tm = fb.st_atime;
loc->m_tm = fb.st_mtime;
loc->c_tm = fb.st_ctime;
loc->next = NULL;
printf("Directory %s successfully added at %s\n", f_name, dest);
break;
case 4:
printf("Dir Name: ");
scanf("%s", f_name);
printf("Destination: ");
scanf("%s", dest);
rmdir(dest);
printf("The directory has been deleted successfully\n");
break;
default:
printf("Operation doesn't exits\n");
exit(0);
}
printf("Do you want to continue with file operations (Y/N)? ");
scanf(" %c", &c);
if(c == 'y' || c == 'Y')
continue;
else
break;
}
while(1){
printf("Do you want to print Director structure OR Linked List (D/L)? ");
scanf(" %c", &dl);
if(dl == 'd' || dl == 'D')
nftw((argc < 2) ? "." : argv[1], disp, 20, flags);
if(dl == 'l' || dl == 'L')
printll(tmp);
printf("Do you want to continue the print? ");
scanf(" %c", &c);
if(c == 'y' || c == 'Y')
continue;
else
break;
}
free(tmp);
exit(EXIT_SUCCESS);
}
/* ----------------Main exit--------------------*/
/* ----------------Display Dir tree structure --------------------*/
static int disp(const char *fpath,
const struct stat *s,
int typeflag,
struct FTW *ftw){
printf("%-3s\t\t%7jd\t\t%-40s\t\t%ld\n",
(typeflag == FTW_D) ? "d" : (typeflag == FTW_F) ? "f": "???",
s->st_size, fpath, s->st_ino);
return 0;
}
/* ----------------xx-xx-------------------*/
/* -----------------Linked list function ----------------- */
static int linked(const char *fpath,
const struct stat *s,
int typeflag,
struct FTW *ftw){
struct dirent *r;
DIR *d;
int files = 0;
if(typeflag == FTW_D){
d= opendir(fpath);
while((r = readdir(d)) != NULL)
files++;
}
if(typeflag == FTW_F || files == 2){
if(head == NULL){
head = malloc(sizeof(node));
head->ino = s->st_ino;
head->f_size = s->st_size;
head->a_tm = s->st_atime;
head->m_tm = s->st_mtime;
head->c_tm = s->st_ctime;
head->next = NULL;
tmp = head;
} else if(head != NULL) {
node *c = (struct node *)malloc(sizeof(node));
c->ino = s->st_ino;
c->f_size = s->st_size;
c->a_tm = s->st_atime;
c->m_tm = s->st_mtime;
c->c_tm = s->st_ctime;
c->next = NULL;
add_at_end(c);
}
}
return 0;
}
/* ------------------xx-------xx--------------------------- */
/* ---------------function to add at end ---------------- */
void add_at_end(node *p){
node *c2 = (struct node *)malloc(sizeof(node));
c2 = tmp;
while(c2->next != NULL)
c2 = c2->next;
c2->next = p;
}
/* --------------------------x--x-------------------------*/
/* -----------------------Printing linked list ------------------------- */
void printll(node *head){
node *ptr;
if(head == NULL)
printf("The linked list is NULL\n");
ptr = head;
while(ptr != NULL){
printf("%ld\n", ptr->ino);
printf("%ld\n", ptr->f_size);
printf("%ld\n", ptr->a_tm);
printf("%ld\n", ptr->m_tm);
printf("%ld\n", ptr->c_tm);
ptr = ptr->next;
printf("\n");
}
}
/* ------------------------x---x--------------------------------------- */
How to get stack trace for C/C++ program in CYGWIN environment ?
** I was looking for a back trace mechanism, I've compiled some of the solutions found here and made it a small program for quick reference.
My Answers with a code snippet:
#if defined(__CYGWIN__)
#include <Windows.h>
#include <dbghelp.h>
#include <psdk_inc/_dbg_common.h>
#include <cxxabi.h>
#include <cstring>
class Error // Windows version
{
private:
void *stacktrace[MAX_STACKTRACE_SIZE];
size_t stacktrace_size;
public:
const char* message;
Error(const char* m)
: message(m)
, stacktrace_size(0)
{
// Capture the stack, when error is 'hit'
stacktrace_size = CaptureStackBackTrace(0, MAX_STACKTRACE_SIZE, stacktrace, nullptr);
}
void print_backtrace(ostream& out) const
{
SYMBOL_INFO * symbol;
HANDLE process;
size_t length;
process = GetCurrentProcess();
SymInitialize(process, nullptr, TRUE);
symbol = (SYMBOL_INFO *)calloc(sizeof(SYMBOL_INFO) + 256 * sizeof(char), 1);
symbol->MaxNameLen = 255;
symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
length = strlen (symbol->Name);
std::string result;
char tempStr[255] = {0};
for (int i = 0; i < stacktrace_size; i++)
{
int status = 0;
// '_' is missing in symbol->Name , hence prefix it and concat with symbol->Name
char prefixed_symbol [256] = "_" ;
SymFromAddr(process, (DWORD64)(stacktrace[i]), 0, symbol);
auto backtrace_line = string(symbol->Name);
if (backtrace_line.size() == 0) continue;
// https://en.wikipedia.org/wiki/Name_mangling
// Prefix '_' with symbol name, so that __cxa_demangle does the job correctly
// $ c++filt -n _Z9test_ringI12SmallIntegerIhEEvRK4RingIT_E
strcat (prefixed_symbol, symbol->Name);
char * demangled_name = abi::__cxa_demangle(prefixed_symbol, nullptr, nullptr, &status);
if(status < 0)
{
sprintf(tempStr, "%i: %s - 0x%0X\n", stacktrace_size-i-1, symbol->Name, symbol->Address);
// out << symbol->Name << endl;
}
else
{
sprintf(tempStr, "%i: %s - 0x%0X\n", stacktrace_size - i - 1, demangled_name, symbol->Address);
// out << demangled_name << endl;
}
// Append the extracted info to the result
result += tempStr;
// Free the HEAP allocation made by __cxa_demangle
free((void*)demangled_name);
// Restore the prefix '_' string
prefixed_symbol [1] = '\0';
}
std::cout << result << std::endl;
free(symbol);
}
};
int main ()
{
try {
do_something ();
if (false == status) throw Error("SystemError");
}
catch (const Error &error)
{
cout << "NotImplementedError(\"" << error.message << "\")" << endl;
error.print_backtrace(cout);
return 1;
}
#endif
Command Line Option:
// Use -limagehlp to link the library
g++ -std=c++20 main.cpp -limagehlp
I would like to create a code that will:
create recursive threads without using loops, the threads has to execute certain routine. I am using Pthread_create on ubuntu
#include <pthread.h>
#include <stdio.h>
#define NUM_THREADS 8
void *PrintHello(void *threadid)
{
printf("\n%d: Hello World!\n", threadid);
pthread_exit(NULL);
}
int main (int argc, char *argv[])
{
pthread_t threads[NUM_THREADS];
int rc, t;
for(t=0; t<NUM_THREADS; t++)
{
printf("Creating thread %d\n", t);
rc = pthread_create(&threads[t], NULL, PrintHello, (void *)t);
if (rc)
{
printf("ERROR; return code from pthread_create() is %d\n", rc);
exit(-1);
}
}
pthread_exit(NULL);
}
Yes you can create thread without using for loop , I have modified your code and used function recursion to create pthread..
#include <pthread.h>
#include <stdio.h>
#define NUM_THREADS 8
pthread_t threads[NUM_THREADS];
void *PrintHello(void *threadid)
{
printf("\n%d: Hello World!\n", threadid);
pthread_exit(NULL);
}
void create_thread(int n){
if (n > 0 ){
//Create thread
printf("Creating thread %d\n", ((NUM_THREADS - n) + 1) );
//NUM_THREADS - n to start index from 0
int rc = pthread_create(&threads[NUM_THREADS - n], NULL, PrintHello, (void *)(NUM_THREADS - n));
if (rc)
{
printf("ERROR; return code from pthread_create() is %d\n", rc);
exit(-1);
}
n--;
create_thread(n);
}
return;
}
int main(int argc, char *argv[])
{
int rc, t;
create_thread( NUM_THREADS );
//Wait to finish all thread
for (t = 0; t < NUM_THREADS; t++)
{
pthread_join(threads[t],NULL);
}
pthread_exit(NULL);
return 0;
}
Hope this will help you.
How can I release the camera when application keeps on running. It is still in on condition. here is the code. I don't know how to release it
#include <cv.h>
#include <highgui.h>
main( int argc, char* argv[] ) {
int i=1;
CvCapture* capture = NULL;
capture = cvCreateCameraCapture( 0 );
IplImage *frames = cvQueryFrame(capture);
while(1) {
if (i==20)
cvReleaseCapture ( &capture );
char c = cvWaitKey(33);
if( c == 27 ) break;
i++;
}
return 0;
}
Your code isn't totally clear so I hope I'm understanding correctly, but I think what you want is something more like this...
#include <cv.h>
#include <highgui.h>
int main( int argc, char* argv[] )
{
int i=1;
CvCapture* capture = NULL;
capture = cvCreateCameraCapture( 0 );
IplImage *frame = cvQueryFrame(capture);
while(1)
{
// if we are on the 20th frame, quit.
if (i==20)
{
cvReleaseCapture ( &capture );
break;
}
// if the user types whatever key 27 corresponds to, quit.
char c = cvWaitKey(33);
if( c == 27 )
{
cvReleaseCapture ( &capture );
break;
}
// do you want to get the next frame? here.
frame = cvQueryFrame( capture );
i++;
}
return 0;
}
Your problem is that you are not breaking after releasing the capture, so you will continue in the loop with a released camera. Also, you had IplImage *frames instead of IplImage *frame. That will only point to a single frame at a time, so I figured renaming it would be helpful for you.
I have a simple client-server application on SCTP! The client connects to server opening 3 streams and the server sends a file per stream. The problem is that I don't know how to control the 3 streams, to know when sctp_rcvmsg() from a stream i 0 it would mean that the file transmission is ended for that stream...but it seems that sctp_recvmsg() never stops. here's my code.
CLIENT
#include <sys/types.h>
#include <sys/socket.h>
#include <signal.h>
#include <netinet/in.h>
#include <netinet/sctp.h>
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <stdlib.h>
#include <time.h>
#define BUFFERSIZE 1024
int main(int argc, char** argv) {
int i, sockCliSCTP, flags, res;
/* Server netwrok informations */
struct sockaddr_in servAddr;
/* To get which stream it has received data from */
struct sctp_sndrcvinfo sndrcvinfo;
/* Init message to setup number of streams */
struct sctp_initmsg initmsg;
/* Catching events */
struct sctp_event_subscribe events;
/* Buffer to receive files */
char buffer[BUFFERSIZE];
/* Remove previous recently used files */
remove("first.txt");
remove("second.txt");
remove("third.txt");
char ipServ[32] = "127.0.0.1";
short int servPort = 29008;
/* BEGIN SCTP PART */
/* Creating client socket for SCTP protocol */
sockCliSCTP = socket( AF_INET, SOCK_STREAM, IPPROTO_SCTP );
/* Specify that a maximum of 3 streams will be available per socket */
memset( &initmsg, 0, sizeof(initmsg) );
initmsg.sinit_num_ostreams = 3; /* output streams */
initmsg.sinit_max_instreams = 3; /* input streams */
initmsg.sinit_max_attempts = 2;
setsockopt(sockCliSCTP, IPPROTO_SCTP, SCTP_INITMSG, &initmsg, sizeof(initmsg) );
/* Initializing server network data structs */
bzero( (void *)&servAddr, sizeof(servAddr) );
servAddr.sin_family = AF_INET;
inet_pton(AF_INET, ipServ, &servAddr.sin_addr);
servAddr.sin_port = htons(29008);
int sizeServ = sizeof(servAddr);
/* Connect to server */
res = connect(sockCliSCTP, (struct sockaddr *)&servAddr, sizeof(servAddr));
if (res < 0) {
printf("Connection to server refused!\n");
exit(1);
}
memset( (void *)&events, 0, sizeof(events) );
events.sctp_data_io_event = 1;
res = setsockopt(sockCliSCTP, SOL_SCTP, SCTP_EVENTS, (const void *)&events, sizeof(events));
if (res < 0) {
printf("setsockopt failed!\n");
exit(1);
}
/* The clients simply waits and receives for three files from the server.
* The size of the files is increased each time this client is launched. */
FILE *oneF, *twoF, *threeF;
oneF = fopen("first.txt", "a"); /* Stream 0 */
twoF = fopen("second.txt", "a"); /* Stream 1 */
threeF = fopen("third.txt", "a"); /* Stream 2 */
/* To measure time */
time_t timeStart;
time_t timeEnd;
time_t timeRes = 0;
time(&timeStart);
int count0 = 0, count1 = 0, count2 = 0;
int checkRead[3];
for(i = 0; i<3; i++) {
checkRead[i] = 1;
}
/* Receiving in parallel the files from 3 streams */
while(checkRead[0] || checkRead[1] || checkRead[2]) {
printf("%d %d %d\n", checkRead[0], checkRead[1], checkRead[2]);
res = sctp_recvmsg(sockCliSCTP, (void*)buffer, sizeof(buffer), (struct sockaddr*)&servAddr, (socklen_t *)&sizeServ, &sndrcvinfo, &flags);
if (res == 0) {
printf("%d stream is zero\n", sndrcvinfo.sinfo_stream);
checkRead[sndrcvinfo.sinfo_stream] = 0;
continue;
}
/* Check from which stream the data came in */
switch(sndrcvinfo.sinfo_stream) {
/* Write on file oneF --> first.txt */
case 0:
count0++;
printf("Message received from stream 0\n");
//printf("%s\n\n", buffer);
fprintf(oneF, "%s", buffer);
break;
/* Write on file twoF --> second.txt */
case 1:
count1++;
printf("Message received from stream 1\n");
//printf("%s\n\n", buffer);
fprintf(twoF, "%s", buffer);
break;
/* Write on file threeF --> third.txt */
case 2:
count2++;
printf("Message received from stream 2\n");
//printf("%s\n\n", buffer);
fprintf(threeF, "%s", buffer);
break;
}
memset(buffer, 0, sizeof(buffer));
sleep(1);
}
close(sockCliSCTP);
time(&timeEnd);
timeRes = timeEnd - timeStart;
printf("Time elapsed is: %d seconds\n", (int)timeRes);
printf("%d messages on stream 0,\n %d messages on stream 1,\n %d messages on stream 2\n", count0, count1, count2);
}
AND THE SERVER:
#include <sys/types.h>
#include <sys/socket.h>
#include <signal.h>
#include <netinet/in.h>
#include <netinet/sctp.h>
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <stdlib.h>
#include <time.h>
#include <sys/stat.h>
#include <fcntl.h>
#define BUFFERSIZE 1024
int main(int argc, char** argv) {
int sockCli, sockServ, one, two, three, i, res;
struct sockaddr_in client, server;
/* data struct to declarate streams */
struct sctp_initmsg initmsg;
/* buffer to read from file */
char buffer[BUFFERSIZE];
/* socket server listening */
sockServ = socket(AF_INET, SOCK_STREAM, IPPROTO_SCTP);
bzero( (void *)&client, sizeof(client));
bzero( (void *)&server, sizeof(server));
/* Preparing sever data struct and bind() */
bzero( (void *)&server, sizeof(server) );
server.sin_family = AF_INET;
server.sin_addr.s_addr = htonl( INADDR_ANY );
server.sin_port = htons(29008);
bind(sockServ, (struct sockaddr *)&server, sizeof(server));
/* Maximum of 3 streams will be available per socket */
memset( &initmsg, 0, sizeof(initmsg) );
initmsg.sinit_num_ostreams = 3;
initmsg.sinit_max_instreams = 3;
initmsg.sinit_max_attempts = 2;
res = setsockopt(sockServ, IPPROTO_SCTP, SCTP_INITMSG, &initmsg, sizeof(initmsg));
if (res < 0) {
printf("setsockopt() failed!\n");
exit(1);
}
/* Preparing the three files to be sent */
one = open("files/first.txt", O_RDONLY);
if (one < 0) {
printf("Error on opening first file!\n");
exit(1);
}
two = open("files/second.txt", O_RDONLY);
if (two < 0) {
printf("Error on opening second file!\n");
exit(1);
}
three = open("files/third.txt", O_RDONLY);
if (three < 0) {
printf("Error on opening third files!\n");
exit(1);
}
int checkFiles[3];
for(i=0; i<3; i++) {
checkFiles[i] = 1;
}
res = listen(sockServ, 5);
if (res < 0) {
printf("listen() failed!\n");
exit(1);
}
while(1) {
ssize_t readRes;
int len = sizeof(client);
sockCli = accept(sockServ, (struct sockaddr*)&client, &len);
if (sockCli < 0) {
printf("Error on accept()!\n");
exit(1);
}
printf("Associated to client!\n");
while(1) {
memset(buffer, 0, sizeof(buffer));
if ((readRes = read(one, (void*)buffer, sizeof(buffer))) > 0) {
sctp_sendmsg(sockCli, (void*)buffer, (size_t)strlen(buffer), NULL, 0, 0, 0, 0 /* stream number */, 0, 0);
}
memset(buffer, 0, sizeof(buffer));
if ((readRes = read(two, (void*)buffer, sizeof(buffer))) > 0) {
sctp_sendmsg(sockCli, (void*)buffer, (size_t)strlen(buffer), NULL, 0, 0, 0, 1 /* stream number */, 0, 0);
}
memset(buffer, 0, sizeof(buffer));
if ((readRes = read(three, (void*)buffer, sizeof(buffer))) > 0) {
sctp_sendmsg(sockCli, (void*)buffer, (size_t)strlen(buffer), NULL, 0, 0, 0, 2 /* stream number */, 0, 0);
}
else {break;}
}
close(sockCli);
close(one);
close(two);
close(three);
}
}
Where am I making a mistake? :(
sctp_recvmsg doesn't receive a message from a single stream. It simply returns ANY message received and then the application can figure out which stream the message came from.
After all the data has been received by your client when this code executes:
res = sctp_recvmsg(sockCliSCTP, (void*)buffer, sizeof(buffer), (struct sockaddr*)&servAddr, (socklen_t *)&sizeServ, &sndrcvinfo, &flags);
if (res == 0) {
printf("%d stream is zero\n", sndrcvinfo.sinfo_stream);
checkRead[sndrcvinfo.sinfo_stream] = 0;
continue;
}
res becomes 0 since no message is received and the sndrcvinfo structure does not get changed. So sndrcvinfo.sinfo_stream will remain equal to whatever stream the last message came from and you will get stuck in a loop since you won't change the checkRead[] values.
There's some other errors that will make the server/client behave strangely.
For example you can't run the client twice in a row without a a segmentation fault since the server closes the file descriptors and won't send any data the second time. Because of this you will segfault when you do:
checkRead[sndrcvinfo.sinfo_stream] = 0;
since sndrcvinfo will be a null pointer.