I need to get list of devices(printers, laptops, ...) and information(ip, MAC, name) for each device at iPhone. I have no idea how. Could anybody help me.
Since you already have the IP-addresses you can query the ARP-table like this
#include <sys/param.h>
#include <sys/file.h>
#include <sys/socket.h>
#include <sys/sysctl.h>
#include <net/if.h>
#include <net/if_dl.h>
#include "if_types.h"
#include "route.h"
#include "if_ether.h"
#include <netinet/in.h>
#include <arpa/inet.h>
#include <err.h>
#include <errno.h>
#include <netdb.h>
#include <paths.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
-(NSString*) ip2mac: (char*) ip
{
static int nflag;
int flags, found_entry;
NSString *mAddr = nil;
u_long addr = inet_addr(ip);
int mib[6];
size_t needed;
char *host, *lim, *buf, *next;
struct rt_msghdr *rtm;
struct sockaddr_inarp *sin;
struct sockaddr_dl *sdl;
extern int h_errno;
struct hostent *hp;
mib[0] = CTL_NET;
mib[1] = PF_ROUTE;
mib[2] = 0;
mib[3] = AF_INET;
mib[4] = NET_RT_FLAGS;
mib[5] = RTF_LLINFO;
if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
err(1, "route-sysctl-estimate");
if ((buf = malloc(needed)) == NULL)
err(1, "malloc");
if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
err(1, "actual retrieval of routing table");
lim = buf + needed;
for (next = buf; next < lim; next += rtm->rtm_msglen) {
rtm = (struct rt_msghdr *)next;
sin = (struct sockaddr_inarp *)(rtm + 1);
sdl = (struct sockaddr_dl *)(sin + 1);
if (addr) {
if (addr != sin->sin_addr.s_addr)
continue;
found_entry = 1;
}
if (nflag == 0)
hp = gethostbyaddr((caddr_t)&(sin->sin_addr),
sizeof sin->sin_addr, AF_INET);
else
hp = 0;
if (hp)
host = hp->h_name;
else {
host = "?";
if (h_errno == TRY_AGAIN)
nflag = 1;
}
if (sdl->sdl_alen) {
u_char *cp = LLADDR(sdl);
mAddr = [NSString stringWithFormat:#"%x:%x:%x:%x:%x:%x", cp[0], cp[1], cp[2], cp[3], cp[4], cp[5]];
// ether_print((u_char *)LLADDR(sdl));
}
else
mAddr = nil;
}
if (found_entry == 0) {
return nil;
} else {
return mAddr;
}
}
- (void)viewDidLoad
{
[super viewDidLoad];
NSString *s = #"0.0.0.0";
const char *c = [s UTF8String];
NSLog(#"MAC IS %#", [self ip2mac:c]);
}
And you need to add these classes to your project classes
"if_types.h"
"route.h"
"if_ether.h"
This function takes an IP-address string (x.x.x.x) as arg and returns the mac address as a string.
Related
This is how I receive layer 3 frame from TUN.
Written based on docs:
https://www.kernel.org/doc/Documentation/networking/tuntap.txt
http://backreference.org/2010/03/26/tuntap-interface-tutorial/
Unpacking from http://www.saminiir.com/lets-code-tcp-ip-stack-1-ethernet-arp/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <net/if.h>
#include <linux/if_tun.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <arpa/inet.h>
#include <sys/select.h>
#include <sys/time.h>
#include <errno.h>
#include <stdarg.h>
/* buffer for reading from tun/tap interface, must be >= 1500 */
#define BUFSIZE 2000
int tun_alloc(char *dev)
{
struct ifreq ifr;
int fd, err;
if (!dev) {
return -1;
}
memset(&ifr, 0, sizeof(ifr));
/* Flags: IFF_TUN - TUN device (no Ethernet headers)
* IFF_TAP - TAP device
*
* IFF_NO_PI - Do not provide packet information
* IFF_MULTI_QUEUE - Create a queue of multiqueue device
*/
ifr.ifr_flags = IFF_TUN;
strcpy(ifr.ifr_name, dev);
if ((fd = open("/dev/net/tun", O_RDWR)) < 0)
return fd;
err = ioctl(fd, TUNSETIFF, (void *)&ifr);
if (err) {
close(fd);
goto err;
}
strcpy(dev, ifr.ifr_name);
return fd;
err:
close(fd);
return err;
}
int main() {
char *tun_name;
tun_name = malloc(IFNAMSIZ);
tun_name[0] = '\0';
int tun_fd = tun_alloc(tun_name);
if (tun_fd < 0) {
puts("Try as root");
exit(1);
}
if (ioctl(tun_fd, TUNSETPERSIST, 0) < 0) {
perror("disabling TUNSETPERSIST");
exit(1);
}
printf("Set interface '%s' nonpersistent\n", tun_name);
struct layer3_frame
{
uint16_t flags;
uint16_t proto;
uint8_t version;
unsigned char payload[];
} __attribute__((packed));
int nread;
char buffer[BUFSIZE];
while(1) {
nread = read(tun_fd, buffer, sizeof(buffer));
if(nread < 0) {
perror("Reading from interface");
close(tun_fd);
exit(1);
}
/* Do whatever with the data */
printf("Read %d bytes from device %s\n", nread, tun_name);
struct layer3_frame* l3f = (struct layer3_frame*)(buffer);
printf("FLAGS %d, PROTO %d, VER %d", l3f->flags, l3f->proto, l3f->version);
// E.g. FLAGS 0, PROTO 56710, VER 96
// Why PROTO is not 4 or 6, why VER is not 4 or 6?
// MAIN: HOW TO USE PCAP TO PARSE l3f FURTHER
// AND GET INFO UP TO SNI (server name indication), e.g.
}
return 0;
}
To play:
gcc index.c
sudo ./a.out
sudo ip link set tun0 up
PCAP usually is not used for parsing packets.
You may use however:
#include <netinet/ip.h>
#include <netinet/ip6.h>
//...
struct layer3_frame
{
uint16_t flags; // FLAGS from TUN
uint16_t proto; // PRPTO from TUN
unsigned char payload[]; // FRAME/PACKET
} __attribute__((packed));
const struct ip* ippacket = (struct ip*)(l3p->payload);
printf("Version is %d", ippacket->ip_v)
3. About strange values for PROTO like 56710 try printf("FFF: %x", ntohs(56710)) you will get 86dd which you may look up at https://en.wikipedia.org/wiki/EtherType
I am trying to run a TCP server on iOS from Cellular. For purposes of asking this question, I wrote this very simplified version of a server and client in C using socket/bind/listen/accept/etc. This works fine when I run the server program from a server. When I run the server program from an iOS app via Cellular (no Wifi), the client never connects to the server. Here is my code:
Server:
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <pthread.h>
#include "tcp_server_IPv4.h"
#define SZ_SOCKADDR_IN sizeof(struct sockaddr_in)
void pfail(char *w) {
printf("pfail %s\n", w);
perror(w);
exit(1);
}
void *tcp_server_IPv4_thread_routine(void *arg) {
int tcp4_sockfd = 0, tcp4_new_fd = 0;
char wes[64];
tcp4_sockfd = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in their_addr = {0};
struct sockaddr_in serv_addr = {0};
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(0);
int br = bind(tcp4_sockfd, (struct sockaddr*)&serv_addr, SZ_SOCKADDR_IN);
if (br == -1) {
pfail("PROBLEM BINDING");
}
int lr = listen(tcp4_sockfd, 5);
if (lr == -1) {
pfail("PROBLEM LISTENING");
}
socklen_t gsn_len = sizeof(serv_addr);
int gsn = getsockname(tcp4_sockfd, (struct sockaddr*)&serv_addr, &gsn_len);
if (gsn == -1) pfail("getsockname");
inet_ntop(AF_INET, &serv_addr, wes, sizeof(wes));
printf("start listening on (%s) port (%d)...", wes, ntohs(serv_addr.sin_port));
int tcp_running = 1;
while (tcp_running) { // main accept() loop
socklen_t sin_size = sizeof their_addr;
tcp4_new_fd = accept(tcp4_sockfd, (struct sockaddr *)&their_addr, &sin_size);
if (tcp4_new_fd == -1) {
perror("accept");
continue;
}
inet_ntop(their_addr.sin_family, &their_addr.sin_addr, wes, sizeof wes);
printf("server: got connection from %s\n", wes);
if (!fork()) { // this is the child process
close(tcp4_sockfd); // child doesn't need the listener
if (send(tcp4_new_fd, "Hello, world!", 13, 0) == -1)
perror("send");
close(tcp4_new_fd);
exit(0);
}
close(tcp4_new_fd); // parent doesn't need this
}
pthread_exit("exiting fire_up_tcp thread normally");
}
void start_tcp_server_IPv4() {
pthread_t tcpt4;
char *w4 = "TCP server IPv4 thread";
int pr4 = pthread_create(&tcpt4, NULL, tcp_server_IPv4_thread_routine, (void *)w4);
if (pr4) pfail("create thread for fire_up_tcp_server_v4");
}
Client:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <netdb.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#define PORT_NUMBER 57020
#define SERVER_ADDRESS "70.208.71.248"
#define MAXDATASIZE 200 // max number of bytes we can get at once
int main(int argc, char *argv[]) {
int sockfd, numbytes;
char buf[MAXDATASIZE];
char ip_str[INET6_ADDRSTRLEN];
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
perror("client: socket");
exit(1);
}
struct sockaddr_in sa_server = {0};
sa_server.sin_family = AF_INET;
inet_pton(AF_INET, SERVER_ADDRESS, &(sa_server.sin_addr));
sa_server.sin_port = htons(PORT_NUMBER);
inet_ntop(AF_INET, &sa_server.sin_addr, ip_str, sizeof ip_str);
printf("Try connecting to (%s)(%d)\n", ip_str, ntohs(sa_server.sin_port));
if (connect(sockfd, (struct sockaddr *)&sa_server, sizeof(struct sockaddr_in)) == -1) {
fprintf(stderr, "Error on connect --> %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
puts("CLIENT::Connection successful.");
char fr[128];
sprintf(fr, "Some text here to send");
if (send(sockfd, fr, sizeof fr, 0) < 0) {
fprintf(stderr, "Error on send --> %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
if ((numbytes = recv(sockfd, buf, MAXDATASIZE-1, 0)) == -1) {
perror("recv");
exit(1);
}
buf[numbytes] = '\0';
printf("client: received '%s'\n",buf);
close(sockfd);
return 0;
}
Results from running getifaddrs() on the iOS device. All pdp_ip addresses are up and running:
(interface)(family)(ip)
(lo0)(2)(127.0.0.1)
(lo0)(30)(::1)
(lo0)(30)
(pdp_ip0)(2)(100.114.61.107)
(pdp_ip0)(30)(fe80::4d5:31ee:ba73:d63a)
(pdp_ip0)(30)(2600:1001:b101:600d:1076:2a12:b461:2a02)
(pdp_ip0)(30)(2600:1001:b101:600d:89e3:c982:c32a:b6b2)
(pdp_ip2)(30)(fe80::18b6:a5a7:33a2:13f6)
(pdp_ip2)(30)(2600:1001:812f:cec5:49:69a:d1b9:cc47)
(pdp_ip2)(30)(2600:1001:812f:cec5:e936:25c5:702:e067)
(pdp_ip2)(30)(2600:1001:812f:cec5:48de:1765:5cb5:d56c)
(en2)(30)(fe80::10d5:2496:594f:ff72)
(en2)(2)(169.254.249.210)
(ipsec1)(30)(fe80::26f0:94ff:fe9a:50bc)
(utun0)(30)(fe80::99a1:9bf7:428e:8166)
(utun1)(30)(fe80::4b1d:be95:bbf2:bf02)
(utun2)(30)(fe80::1748:1a1a:c5ee:bda9)
(utun3)(30)(fe80::d3c1:79bc:7613:ffb)
(utun4)(30)(fe80::d3c8:e837:ba74:67dc)
How can I find the text segment (AKA code segment) range in iOS? Meaning, what is the start address and the end address of the text segment?
I found this interesting post but it works for me on Android but not on iOS.
After some digging and expert help (thanks Moshe Kravchik) I got to the desired solution - getting the text segment range by parsing the mach header and retrieving the load commands, segments and sections.
#include <mach-o/dyld.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dlfcn.h>
#import <Foundation/Foundation.h>
#define PRINT_STR "Found __text Section of %s, addr 0x%x, size %u, offset 0x%x, calc address 0x%x"
#define LC_SEGMENT_NATIVE LC_SEGMENT
#define segment_command_native segment_command
#define section_native section
struct libRange
{
uint32_t start;
uint32_t end;
};
void getTextSegmentAddr(struct libRange *txtSegRange)
{
if (txtSegRange==NULL)
return;
txtSegRange->start=0;
const struct mach_header *mach_hdr;
mach_hdr = _dyld_get_image_header(0);
const struct load_command *cmds = (const struct load_command *)(mach_hdr + 1);
uint32_t cmdsleft;
const struct load_command *lc;
for(lc = cmds, cmdsleft = mach_hdr->ncmds; cmdsleft-- && (0 == txtSegRange->start);) {
if(lc->cmd == LC_SEGMENT_NATIVE) {
const struct segment_command_native *sc = (void *) lc;
const struct section_native *sect = (void *) (sc + 1);
for(uint32_t sect_idx = 0; sect_idx < sc->nsects; sect_idx++) {
if(!strcmp("__TEXT", sect->segname) && !strcmp("__text", sect->sectname)) {
uint32_t memAddr = (sc->vmaddr + _dyld_get_image_vmaddr_slide(0) + sect->offset - sc->fileoff);
NSLog(#PRINT_STR,_dyld_get_image_name(0), sect->addr, sect->size, sect->offset, memAddr);
txtSegRange->start = memAddr;
txtSegRange->end = memAddr + sect->size;
break;
}
sect++;
}
}
lc = (void *) ((char *) lc + lc->cmdsize);
}
}
int main()
{
struct libRange txtSegRange;
getTextSegmentAddr(&txtSegRange);
return 0;
}
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.
So I have this problem. I have an IplImage that i want to compress to JPEG and do something with it. I use libjpeg8b.The code exit when it goes the function of jpeg_start_compress() with an error of "Bogus input colorspace" .Here are my code.
#include "highgui.h"
#include <stdio.h>
#include "jpeglib.h"
#include "cv.h"
#include <iostream>
#include <fstream>
using namespace std;
using namespace cv;
#pragma comment(lib, "jpeglib.lib")
bool ipl2jpeg(IplImage *frame, unsigned char **outbuffer, unsigned long*outlen)
{
IplImage *img = new IplImage;
memcpy(img,frame,frame->nSize);
unsigned char *outdata = (uchar *) img->imageData;
struct jpeg_compress_struct cinfo = {0};
struct jpeg_error_mgr jerr;
JSAMPROW row_ptr[1];
int row_stride;
*outbuffer = NULL;
*outlen = 0;
cinfo.err = jpeg_std_error(&jerr);
jpeg_create_compress(&cinfo);
jpeg_mem_dest(&cinfo, outbuffer, outlen);
cinfo.image_width = frame->width;
cinfo.image_height = frame->height;
cinfo.input_components = frame->nChannels;
cinfo.in_color_space = JCS_RGB;
jpeg_set_defaults(&cinfo);
jpeg_start_compress(&cinfo, TRUE);
system("pause");
row_stride = frame->width * frame->nChannels;
while (cinfo.next_scanline < cinfo.image_height)
{
row_ptr[0] = &outdata[cinfo.next_scanline * row_stride];
jpeg_write_scanlines(&cinfo, row_ptr, 1);
}
jpeg_finish_compress(&cinfo);
jpeg_destroy_compress(&cinfo);
return true;
}
int main()
{
ofstream fout("text.txt");
unsigned char **buf;
buf = new unsigned char* [120];
for(int i=0;i<500;i++)
{
buf[i] = new unsigned char[120];
}
for(int i=0;i< 120;i++)
{
for(int j=0;j<120;j++)
{
buf[i][j] = 0;
}
}
unsigned long *len = new unsigned long;
*len = 120*120;
Ptr<IplImage> img = cvLoadImage("test.jpg",CV_LOAD_IMAGE_GRAYSCALE);
ipl2jpeg(img,buf,len);
for(int i=0;i< 120;i++)
{
for(int j=0;j<120;j++)
{
fout<<buf[i][j]<<endl;
}
}
return 0;
}
I've never used libjpeg before, but it looks like you're mixing color spaces. You load the image as a grayscale (CV_LOAD_IMAGE_GRAYSCALE), but are telling libjpeg that it's an RGB image (JCS_RGB). Have you tried changing the line
cinfo.in_color_space = JCS_RGB;
to
cinfo.in_color_space = JCS_GRAYSCALE;
?
Is there any reason why you're not using opencv's native JPEG support?
cvSaveImage(frame, "frame.jpeg");
The documentation is here.
EDIT
If you insist on using libjpeg, have a look at this post.